我有几个类似于以下代码片段的 DataContract
:
[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
[DataMember(IsRequired = true)]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
[DataMember(IsRequired = true)]
public int Id { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
之前我没有注意到序列化消息,但最近进行了两个更改:我添加了一个名为ReturnCode
的新属性,并运行CodeMaid的“重新组织”功能,使属性按字母顺序排列。
现在它看起来像这样:
[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
public ExtensionDataObject ExtensionData { get; set; }
[DataMember(IsRequired = true)]
public int Id { get; set; }
[DataMember(IsRequired = true)]
public string Name { get; set; }
[DataMember]
public int ReturnCode { get; set; }
[DataMember]
public string Value { get; set; }
}
根据微软有关“数据契约成员顺序”页面(http://msdn.microsoft.com/en-us/library/ms729813(v=vs.110).aspx)的说明,我意识到“ReturnCode”会破坏契约,因为序列化程序会在“Value”之前插入它。因此,我添加了一个“Order”属性值,假定原始顺序是字母顺序,最终代码如下:
[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
public ExtensionDataObject ExtensionData { get; set; }
[DataMember(IsRequired = true, Order = 0)]
public int Id { get; set; }
[DataMember(IsRequired = true, Order = 1)]
public string Name { get; set; }
[DataMember(Order = 3)]
public int ReturnCode { get; set; }
[DataMember(Order = 2)]
public string Value { get; set; }
}
然而,这引发了一个异常,即反序列化的成员顺序不正确。我回滚到以前的变更集,即所有变更之前,并且确实在 SOAP 请求中(通过Fiddler查看)成员的原始顺序不是按字母顺序排序的,而是按代码中表示的原始顺序排序,即:
Name
、Value
、Id
。
我目前正在添加Order
值到所有旧的DTO类型中,以根据它们以前的、未按字母排序的属性排列功能对它们进行排序。我想知道为什么序列化器使用编码顺序而不是按字母顺序排序?微软的规则说:
接下来是当前类型的数据成员,没有设置DataMemberAttribute属性的Order属性,按字母顺序排列。
更新:
在我添加了Order
值以根据它们的原始顺序对属性进行排序之后,我再次运行Fiddler,它仍然使用项目按字面编码的顺序。换句话说,由于某种原因,我的 WCF 服务完全忽略了任何序列化排序逻辑,并且只是按它们出现在 .cs 文件中的顺序对属性进行排序。实际上,我能够使其正确序列化的唯一方法是将每个类型中的属性物理重新排列到它们的原始顺序。虽然这样可以工作,但这不是首选方式。
更新2-解决方案:
根据Dracor的建议,我向我的DTO添加了[XmlElement(Order = 1)]
属性和一个XmlRootAttribute
。SOAP序列化确实遵循了这些属性分配的顺序。我没有考虑过,但我的服务确实使用Castle DynamicProxy,所以我猜它正在将序列化程序从DataContractSerializer
更改为XmlSerializer
。
DataContractSerializer
。 - Nick Gotch