如何以向后兼容的方式向 DTO 添加属性?
Posted
技术标签:
【中文标题】如何以向后兼容的方式向 DTO 添加属性?【英文标题】:How to add property to DTO in a backward compatible way? 【发布时间】: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 模式,但当模式开始发生变化时就会成为一场噩梦。 【参考方案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。
注意事项:
要将自动实现的属性的支持字段标记为可选,请参阅NetDataContractSerializer Deserialization With New Property。
话虽如此,我不建议使用 [Serializable]
类型的自动属性,因为序列化流将包含秘密支持字段的名称。详情请见.NET WebAPI Serialization k_BackingField Nastiness。
您已用[XmlAttribute]
标记了您的类型,但DataContractSerializer
忽略了此属性。它只影响XmlSerializer
的序列化。
演示小提琴here.
【讨论】:
以上是关于如何以向后兼容的方式向 DTO 添加属性?的主要内容,如果未能解决你的问题,请参考以下文章