DataContractSerializer 是否仅适用于 http://schemas.datacontract.org/2004/07/

Does DataContractSerializer work only with http://schemas.datacontract.org/2004/07/

我遇到了一个问题,我的对象没有从 Post 请求的主体中反序列化,我遵循了 this answer 这说明因为 WebApi 默认使用 DataContractSerializer,你需要定义你的xmlns这样

<TestModel 
xmlns="http://schemas.datacontract.org/2004/07/YourMvcApp.YourNameSpace">

确实有效,但如果我更改年份或月份,如 http://schemas.datacontract.org/2005/07/...,它会停止工作并且我的对象再次变为 null。

为什么会这样,http://schemas.datacontract.org/2004/07/ 是否以某种方式进行了硬编码?为什么这个 URL,究竟是什么?

每个数据合同对象都由一个完全限定的数据合同名称标识。如 Data Contract Names 中所述:

Basic rules regarding naming data contracts include:

  • A fully-qualified data contract name consists of a namespace and a name.
  • Data members have only names, but no namespaces.
  • When processing data contracts, the WCF infrastructure is case-sensitive to both the namespaces and the names of data contracts and data members.

A data contract namespace takes the form of a Uniform Resource Identifier (URI). The URI can be either absolute or relative. By default, data contracts for a particular type are assigned a namespace that comes from the common language runtime (CLR) namespace of that type.

By default, any given CLR namespace (in the format Clr.Namespace) is mapped to the namespace "http://schemas.datacontract.org/2004/07/Clr.Namespace". To override this default, apply the ContractNamespaceAttribute attribute to the entire module or assembly. Alternatively, to control the data contract namespace for each type, set the Namespace property of the DataContractAttribute.

Data Contract Equivalence中:

For data contracts to be equivalent, they must have the same namespace and name. Additionally, each data member on one side must have an equivalent data member on the other side.

因此,要通过网络成功发送数据协定对象,完全限定的数据协定名称必须在两端匹配。如上所述,默认数据协定命名空间是 http://schemas.datacontract.org/2004/07/Clr.Namespace,但您可能希望更改它以以某种方式反映您的组织,例如:

[DataContract(Namespace = "http://schemas.MyOrganization.com/v1")]
public class TestModel 
{
    [DataMember]
    public string Value { get; set; }
}

或者您可以为整个程序集和 .Net 命名空间设置它:

[assembly: ContractNamespace("http://schemas.MyOrganization.com/v1", ClrNamespace = "YourMvcApp.YourNameSpace")]

数据契约序列化可用于JSON和XML,那么DataContractSerializer如何将数据契约名称映射到XML?它使用 XML 元素本地名称和命名空间 URI:

<TestModel xmlns="http://schemas.datacontract.org/2004/07/YourMvcApp.YourNameSpace">

xmlns="http://schemas.datacontract.org/2004/07/YourMvcApp.YourNameSpace"属性是元素的default XML namespace declaration of the element with local name TestModel. The local name and namespace together comprise the expanded name。如果命名空间 URI 和本地名称匹配,XML 元素名称被认为是相等的,因此 Microsoft 选择将数据协定名称对应到 XML 元素局部名称,并将数据协定命名空间对应到 XML 命名空间 URI,这就是为什么更改 甚至 URI 中的年或月 会导致反序列化失败。

因此,如您所见,命名空间的选择需要在推出数据合同 Web API 或 WCF 服务之前确定,因为更改命名空间需要在客户端更新命名空间。 (当然,对于 WCF,客户端通常会根据解释的模式元数据自动生成客户端,例如 here or here。)