我通常在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 override void SerializeOwnedData(SerializationWriter writer, object context)
{
base.SerializeOwnedData(writer, context);
byte serializeVersion = 4;
writer.Write(serializeVersion);
writer.Write(CustomerNumber);
writer.Write(PopulationRegistryNumber);
writer.Write(HomeAddress);
writer.Write(ZipCode);
writer.Write(HomeCity);
if (CustomerCards == null)
CustomerCards = new List<uint>();
writer.Write(CustomerCards);
writer.Write(HomeAddressObj);
writer.Write(County);
// v 2
writer.Write(Muni);
// v 4
if (_AvailableCustomers == null)
_AvailableCustomers = new List<uint>();
writer.Write(_AvailableCustomers);
}
因此,如果选择的话,很容易添加新内容或完全更改序列化。
但是,我现在想要使用JSON,因为这里不相关的原因=)我目前正在使用 DataContractJsonSerializer ,我现在正在寻找一种方法来获得我使用上面的FastSerializer所具有的相同的灵活性
所以问题是;什么是创建JSON协议/序列化的最佳方法,并且能够如上所述详细说明序列化,以便我不会因为另一台机器尚未更新其版本而中断序列化?
答案 0 :(得分:32)
版本控制JSON的关键是始终添加新属性,并且永远不会删除或重命名现有属性。这类似于how protocol buffers handle versioning。
例如,如果您使用以下JSON开始:
{
"version": "1.0",
"foo": true
}
并且您想将“foo”属性重命名为“bar”,不要只重命名它。而是添加一个新属性:
{
"version": "1.1",
"foo": true,
"bar": true
}
由于您永远不会删除属性,因此基于旧版本的客户端将继续工作。这种方法的缺点是随着时间的推移JSON会变得臃肿,你必须继续维护旧的属性。
向客户明确定义“边缘”案例也很重要。假设您有一个名为“fooList”的数组属性。 “fooList”属性可以采用以下可能的值:不存在/未定义(该属性实际上不存在于JSON对象中,或者存在且设置为“未定义”),null,空列表或包含一个或多个值。客户端了解如何操作非常重要,尤其是在undefined / null / empty情况下。
我还建议您阅读semantic versioning的工作原理。如果您为版本号引入语义版本控制方案,则可以在次要版本边界上进行向后兼容的更改,同时可以在主要版本边界上进行更改(客户端和服务器都必须就相同的主要版本达成一致) )。虽然这不是JSON本身的属性,但这对于传达客户端在版本更改时应该期望的更改类型非常有用。
答案 1 :(得分:16)
Google基于java的gson library对json提供了出色的版本支持。如果您正在考虑使用java方式,它可能会非常方便。
有一个很好的简单教程here。
答案 2 :(得分:7)
不要使用DataContractJsonSerializer,正如名称所示,通过此类处理的对象必须:
a)标有[DataContract]和[DataMember]属性。
b)严格遵守已定义的“合同”,即合同中的任何内容,仅限定义。任何额外的或缺少的[DataMember]都会使反序列化抛出异常。
如果你想要足够灵活,那么如果你想购买便宜的选项,请使用JavaScriptSerializer ......或者使用这个库:
这将为您提供对JSON序列化的充分控制。
想象一下,你早期就有一个物体。
public class Customer
{
public string Name;
public string LastName;
}
序列化后,它将如下所示:
{姓名:“John”,姓氏:“Doe”}
如果您更改对象定义以添加/删除字段。如果您使用JavaScriptSerializer,则反序列化将顺利进行。
public class Customer
{
public string Name;
public string LastName;
public int Age;
}
如果你试图将最后一个json反序列化为这个新类,则不会抛出任何错误。问题是您的新字段将设置为默认值。在此示例中:“Age”将设置为零。
您可以在自己的约定中包含所有对象中包含版本号的字段。在这种情况下,您可以区分空字段或版本不一致。
所以我们说:你的班级客户v1被序列化了:
{ Version: 1, LastName: "Doe", Name: "John" }
您希望反序列化为Customer v2实例,您将拥有:
{ Version: 1, LastName: "Doe", Name: "John", Age: 0}
你可以以某种方式检测对象中的哪些字段以某种方式可靠,哪些字段不可靠。在这种情况下,您知道您的v2对象实例来自v1对象实例,因此不应信任Age字段。
我记得您还应该使用自定义属性,例如“MinVersion”,并用最小支持的版本号标记每个字段,所以你得到这样的东西:
public class Customer
{
[MinVersion(1)]
public int Version;
[MinVersion(1)]
public string Name;
[MinVersion(1)]
public string LastName;
[MinVersion(2)]
public int Age;
}
然后,您可以访问此元数据,并使用它执行您可能需要的任何操作。