【问题标题】:How to add property to DTO in a backward compatible way?如何以向后兼容的方式向 DTO 添加属性?
【发布时间】:2021-10-10 18:34:33
【问题描述】:

WCF 用于在客户端和服务器之间传输数据。旧 DTO:

[Serializable]
public class TestClass
{
    private string firstProperty;

    [XmlAttribute]
    public string FirstProperty
    {
        get => firstProperty;
        set => firstProperty = value;
    }
}

客户将继续发送旧版本。 该类需要扩展为如下所示:

[Serializable]
public class TestClass
{
    private string firstProperty;
    private string secondProperty;
    
    [XmlAttribute]
    public string FirstProperty
    {
        get => firstProperty;
        set => firstProperty = value;
    }

    [XmlAttribute]
    public string SecondProperty
    {
        get => secondProperty;
        set => secondProperty = value;
    }
}

序列化:

public static void SerializeDataContract<T>(T obj, string path)
{
    var serializer = new DataContractSerializer(typeof(T));
    var settings = new XmlWriterSettings { Indent = true };
    using (var writer = XmlWriter.Create(path, settings))
    {
        serializer.WriteObject(writer, obj);
    }
}

public static T DeserializeDataContract<T>(string path)
{
    var serializer = new DataContractSerializer(typeof(T));
    using (var s = File.OpenRead(path))
    {
        return (T) serializer.ReadObject(s);
    }
}

服务器和部分客户端将使用新版本。如果我将旧版本序列化并反序列化到新版本中,则会抛出以下错误:

System.Runtime.Serialization.SerializationException:'第 1 行位置 129 中的错误。'EndElement''TestClass' 来自命名空间'http://schemas.datacontract.org/2004/07/DTOs' 不是预期的。期望元素“secondProperty”。'

异常通常在 WCF 层中引发,但我提取了一个最小的可重现示例。 如果我使用 XmlSerializer 错误就消失了。但是更改序列化器不是一种选择,因为旧客户端将继续使用 DataContractSerializer。

因此,由于 XmlSerializer 属性与 DataContractSerializer 相结合,我很难让它工作。有什么建议吗?

【问题讨论】:

  • 试试 OptionalFieldAttribute 类,它指定一个字段可以从序列化流中丢失,这样 BinaryFormatter 和 SoapFormatter 就不会抛出异常。
  • 告诉您这些可能为时已晚,但您在应用程序中使用的“数据绑定”方法非常适合简单稳定的 XML 模式,但当模式开始发生变化时就会成为一场噩梦。

标签: c# xml wcf datacontractserializer


【解决方案1】:

您可以通过标记[OptionalFieldAttribute] 来表明secondProperty 是可选的:

[Serializable]
public class TestClass
{
    private string firstProperty;

    [OptionalField]
    private string secondProperty;

    [XmlAttribute]
    public string FirstProperty
    {
        get => firstProperty;
        set => firstProperty = value;
    }

    [XmlAttribute]
    public string SecondProperty
    {
        get => secondProperty;
        set => secondProperty = value;
    }
}

当一个类型被标记为[Serializable] 而不是data contract attributes 时,数据协定序列化程序将序列化该类型实例的公共和私有字段——而不是属性——在一个方式类似于BinaryFormatter。因此,除非标有[OptionalField],否则所有字段都必须存在。

如需了解更多信息,请参阅 Types Supported by the Data Contract Serializer 和 Version tolerant serialization: Tolerance of missing data。

注意事项:

演示小提琴here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多