如何以向后兼容的方式将 属性 添加到 DTO?
How to add property to DTO in a backward compatible way?
WCF 用于在客户端和服务器之间传输数据。旧 DTO:
[Serializable]
public class TestClass
{
private string firstProperty;
[XmlAttribute]
public string FirstProperty
{
get => firstProperty;
set => firstProperty = value;
}
}
客户将继续发送旧版本。
class 需要扩展为如下所示:
[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: 'Error in line 1 position 129. 'EndElement' 'TestClass' from namespace 'http://schemas.datacontract.org/2004/07/DTOs' is not expected. Expecting element 'secondProperty'.'
异常通常在 WCF 层中引发,但我提取了一个最小的可重现示例。
如果我使用 XmlSerializer,错误就消失了。但是更改序列化程序不是一种选择,因为旧客户端将继续使用 DataContractSerializer。
由于 XmlSerializer 属性与 DataContractSerializer 的结合,我很难让它工作。有什么建议吗?
您可以通过用 [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]
but not data contract attributes 时,数据协定序列化程序将序列化该类型实例的 public 和私有 字段 -- 不是属性 - 以类似于 BinaryFormatter
的方式。因此,除非标有 [OptionalField]
.
,否则所有字段都必须存在
有关更多信息,请参阅 Types Supported by the Data Contract Serializer and Version tolerant serialization: Tolerance of missing data。
备注:
要将自动实现的 属性 的支持字段标记为可选,请参阅 NetDataContractSerializer Deserialization With New Property。
也就是说,我不建议使用 [Serializable]
类型的自动属性,因为序列化流将包含秘密支持字段的名称。有关详细信息,请参阅 .NET WebAPI Serialization k_BackingField Nastiness。
您已用 [XmlAttribute]
, but this attribute is ignored by DataContractSerializer
. It only affects serialization by XmlSerializer
标记您的类型。
演示 fiddle here.
WCF 用于在客户端和服务器之间传输数据。旧 DTO:
[Serializable]
public class TestClass
{
private string firstProperty;
[XmlAttribute]
public string FirstProperty
{
get => firstProperty;
set => firstProperty = value;
}
}
客户将继续发送旧版本。 class 需要扩展为如下所示:
[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: 'Error in line 1 position 129. 'EndElement' 'TestClass' from namespace 'http://schemas.datacontract.org/2004/07/DTOs' is not expected. Expecting element 'secondProperty'.'
异常通常在 WCF 层中引发,但我提取了一个最小的可重现示例。 如果我使用 XmlSerializer,错误就消失了。但是更改序列化程序不是一种选择,因为旧客户端将继续使用 DataContractSerializer。
由于 XmlSerializer 属性与 DataContractSerializer 的结合,我很难让它工作。有什么建议吗?
您可以通过用 [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]
but not data contract attributes 时,数据协定序列化程序将序列化该类型实例的 public 和私有 字段 -- 不是属性 - 以类似于 BinaryFormatter
的方式。因此,除非标有 [OptionalField]
.
有关更多信息,请参阅 Types Supported by the Data Contract Serializer and Version tolerant serialization: Tolerance of missing data。
备注:
要将自动实现的 属性 的支持字段标记为可选,请参阅 NetDataContractSerializer Deserialization With New Property。
也就是说,我不建议使用
[Serializable]
类型的自动属性,因为序列化流将包含秘密支持字段的名称。有关详细信息,请参阅 .NET WebAPI Serialization k_BackingField Nastiness。您已用
[XmlAttribute]
, but this attribute is ignored byDataContractSerializer
. It only affects serialization byXmlSerializer
标记您的类型。
演示 fiddle here.