使用JSON协议处理版本控制的最佳方法是什么?

使用JSON协议处理版本控制的最佳方法是什么?,json,serialization,binary,versioning,Json,Serialization,Binary,Versioning,我通常用C#编写代码的所有部分,在编写序列化的协议时,我使用FastSerializer快速高效地序列化/反序列化类。它也很容易使用,并且相当直接地进行“版本控制”,即处理不同版本的序列化。我通常使用的东西是这样的: public override void DeserializeOwnedData(SerializationReader reader, object context) { base.DeserializeOwnedData(reader, context); b

我通常用C#编写代码的所有部分,在编写序列化的协议时,我使用FastSerializer快速高效地序列化/反序列化类。它也很容易使用,并且相当直接地进行“版本控制”,即处理不同版本的序列化。我通常使用的东西是这样的:

public override void DeserializeOwnedData(SerializationReader reader, object context)
{
    base.DeserializeOwnedData(reader, context);
    byte serializeVersion = reader.ReadByte(); // used to keep what version we are using

    this.CustomerNumber = reader.ReadString();
    this.HomeAddress = reader.ReadString();
    this.ZipCode = reader.ReadString();
    this.HomeCity = reader.ReadString();
    if (serializeVersion > 0)
        this.HomeAddressObj = reader.ReadUInt32();
    if (serializeVersion > 1)
        this.County = reader.ReadString();
    if (serializeVersion > 2)
        this.Muni = reader.ReadString();
    if (serializeVersion > 3)
        this._AvailableCustomers = reader.ReadList<uint>();
}
public class Customer
{ 
    [MinVersion(1)]
    public int Version;

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}
public override void反序列化owneddata(序列化读取器,对象上下文)
{
base.DeserializeOwnedData(读取器,上下文);
byte serializeVersion=reader.ReadByte();//用于保留我们正在使用的版本
this.CustomerNumber=reader.ReadString();
this.HomeAddress=reader.ReadString();
this.ZipCode=reader.ReadString();
this.HomeCity=reader.ReadString();
如果(版本>0)
this.HomeAddressObj=reader.ReadUInt32();
如果(版本>1)
this.County=reader.ReadString();
如果(版本>2)
this.Muni=reader.ReadString();
如果(版本>3)
这是._AvailableCustomers=reader.ReadList();
}

public override void SerializeOwnedData(SerializationWriter-writer,对象上下文)
{            
base.SerializeOwnedData(编写器、上下文);
字节序列化版本=4;
writer.Write(序列化版本);
writer.Write(客户编号);
writer.Write(人口登记号码);
Write.Write(家庭地址);
writer.Write(ZipCode);
作家,作家(家乡);
如果(CustomerCards==null)
CustomerCards=新列表();
writer.Write(客户卡);
writer.Write(HomeAddressObj);
作家。作家(县);
//v2
作家,作家(穆尼);
//V4
if(_AvailableCustomers==null)
_AvailableCustomers=新列表();
writer.Write(_可用的用户);
}
因此,添加新内容或完全更改序列化(如果选择的话)很容易

然而,我现在想使用JSON的原因与此处无关=)我目前正在使用DataContractJsonSerializer,我现在正在寻找一种方法,以获得与使用上述FastSerializer相同的灵活性

所以问题是,;创建JSON协议/序列化并能够如上所述详细说明序列化的最佳方法是什么,这样我就不会因为另一台机器尚未更新其版本而中断序列化?

谷歌基于java的java对JSON有着极好的版本控制支持。如果您正考虑采用java方式,那么它可能非常方便


有一个很好且简单的教程。

不要使用DataContractJsonSerializer,顾名思义,通过此类处理的对象必须:

a) 可以用[DataContract]和[DataMember]属性标记

b) 严格遵守定义的“合同”,即合同定义的任何部分。任何额外的或缺少的[DataMember]都将进行反序列化以引发异常

如果您希望足够灵活,那么如果您希望选择便宜的选项,请使用JavaScriptSerializer。。。或使用此库:

这将使您能够充分控制JSON序列化

想象你有一个早期的物体

public class Customer
{ 
    public string Name;

    public string LastName;
}
一旦序列化,它将如下所示:

public override void DeserializeOwnedData(SerializationReader reader, object context)
{
    base.DeserializeOwnedData(reader, context);
    byte serializeVersion = reader.ReadByte(); // used to keep what version we are using

    this.CustomerNumber = reader.ReadString();
    this.HomeAddress = reader.ReadString();
    this.ZipCode = reader.ReadString();
    this.HomeCity = reader.ReadString();
    if (serializeVersion > 0)
        this.HomeAddressObj = reader.ReadUInt32();
    if (serializeVersion > 1)
        this.County = reader.ReadString();
    if (serializeVersion > 2)
        this.Muni = reader.ReadString();
    if (serializeVersion > 3)
        this._AvailableCustomers = reader.ReadList<uint>();
}
public class Customer
{ 
    [MinVersion(1)]
    public int Version;

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}
{姓名:“约翰”,姓氏:“多伊”}

如果将对象定义更改为添加/删除字段。例如,如果使用JavaScriptSerializer,反序列化将顺利进行

public class Customer
{ 
    public string Name;

    public string LastName;

    public int Age;
}
如果您尝试将最后一个json反序列化到此新类,则不会引发任何错误。问题是,您的新字段将设置为默认值。在本例中,“年龄”将设置为零

您可以在自己的约定中包括所有对象中存在的一个字段,该字段包含版本号。在这种情况下,您可以区分空字段和版本不一致

假设:您已经序列化了类Customer v1:

{ Version: 1, LastName: "Doe", Name: "John" }
如果要反序列化到Customer v2实例中,您将有:

{ Version: 1, LastName: "Doe", Name: "John", Age: 0}
您可以通过某种方式检测对象中的哪些字段以某种方式可靠,哪些字段不可靠。在这种情况下,您知道v2对象实例来自v1对象实例,因此不应信任字段Age

我认为您还应该使用一个自定义属性,例如“MinVersion”,并用支持的最小版本号标记每个字段,这样您可以得到如下结果:

public override void DeserializeOwnedData(SerializationReader reader, object context)
{
    base.DeserializeOwnedData(reader, context);
    byte serializeVersion = reader.ReadByte(); // used to keep what version we are using

    this.CustomerNumber = reader.ReadString();
    this.HomeAddress = reader.ReadString();
    this.ZipCode = reader.ReadString();
    this.HomeCity = reader.ReadString();
    if (serializeVersion > 0)
        this.HomeAddressObj = reader.ReadUInt32();
    if (serializeVersion > 1)
        this.County = reader.ReadString();
    if (serializeVersion > 2)
        this.Muni = reader.ReadString();
    if (serializeVersion > 3)
        this._AvailableCustomers = reader.ReadList<uint>();
}
public class Customer
{ 
    [MinVersion(1)]
    public int Version;

    [MinVersion(1)]
    public string Name;

    [MinVersion(1)]
    public string LastName;

    [MinVersion(2)]
    public int Age;
}

然后,您可以访问此元数据,并根据需要执行任何操作。

对JSON进行版本控制的关键是始终添加新属性,而不要删除或重命名现有属性。这类似于

例如,如果您从以下JSON开始:

{
  "version": "1.0",
  "foo": true
}
如果您想将
“foo”
属性重命名为
“bar”
,请不要只是重命名它。而是添加一个新属性:

{
  "version": "1.1",
  "foo": true,
  "bar": true
}
由于您从不删除属性,因此基于旧版本的客户端将继续工作。这种方法的缺点是JSON可能会随着时间的推移而膨胀,您必须继续维护旧的属性

向客户明确定义“边缘”案例也很重要。假设您有一个名为
的数组属性“傻瓜”
“傻瓜”
属性可能具有以下可能的值:不存在/未定义(该属性在JSON对象中实际不存在,或者它存在并设置为
“未定义”
)、
null
、空列表或具有一个或多个值的列表。客户机了解如何操作非常重要,尤其是在未定义/空/空的情况下

我还建议大家阅读一下工作原理。如果在版本号中引入语义版本控制方案,则可以在次要版本边界上进行向后兼容的更改,而在主要版本边界上(客户端和服务器都是