简体   繁体   English

Xml序列化无法在ASP.NET Web Api中按预期方式工作

[英]Xml Serialization not working as expected in ASP.NET Web Api

We have a Web API which uses a base class for all the models. 我们有一个Web API,它对所有模型都使用基类。 Below is the structure 下面是结构

Base abstract class 基础抽象类

[DataContract(Namespace = "")]
public abstract class Criteria
{
    protected Criteria()
    {
        Offset = 0;
        Limit = 250;
    }
    [DataMember(Name = "offset", Order = 97, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public int? Offset { get; set; }

    [DataMember(Name = "limit", Order = 98, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public int? Limit { get; set; }
}

This implements the base abstract class 这实现了基本抽象类

[DataContract(Name = "insightCriteria", Namespace = "")]
public class InsightCriteria : Criteria
{
    [DataMember(Name = "geography", Order = 95, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    [JsonConverter(typeof(StringEnumConverter))]
    public InsightGeography Geography { get; set; }
}

Actual model which implements above class further 进一步实现上述类的实际模型

[DataContract(Name = "jobReportCriteria", Namespace = "")]
public class JobReportCriteria : InsightCriteria
{
    [DataMember(Name = "groupBy", Order = 1, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    [JsonConverter(typeof(StringEnumConverter))]
    public JobReportGroupings GroupBy { get; set; }

    [DataMember(Name = "timePeriod", Order = 2, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public TimePeriod TimePeriod { get; set; }

    [DataMember(Name = "queryString", Order = 3, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public string QueryString { get; set; }

    [DataMember(Name = "includeTotalClassifiedPostings", Order = 4, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public bool IncludeTotalClassifiedPostings { get; set; }

    [DataMember(Name = "includeTotalUnclassifiedPostings", Order = 5, EmitDefaultValue = false)]
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public bool IncludeTotalUnclassifiedPostings { get; set; }
}

Issue 问题

Now the problem is when using json serialization everything works fine I'm receiving values for offset and limit in the abstract class. 现在的问题是,当使用json序列化时,一切正常,我正在抽象类中接收offset和limit的值。 But when using XML serialization the offset and limit is not getting populated. 但是,当使用XML序列化时,不会填充偏移量和限制。

Below is request I'm passing to api via Rest Client 以下是我通过Rest Client传递给api的请求

<jobReportCriteria>
  <groupBy>State</groupBy>
  <timePeriod>
    <from>2014-02-06T00:00:00</from>
    <to>2014-05-06T00:00:00</to>
  </timePeriod>
  <queryString>[nationwide]: &quot; nationwide &quot;</queryString>
  <includeTotalClassifiedPostings>true</includeTotalClassifiedPostings>
  <includeTotalUnclassifiedPostings>true</includeTotalUnclassifiedPostings>
  <includeLastDataDate>true</includeLastDataDate>
  <offset>0</offset>
  <limit>25</limit>
</jobReportCriteria>

Strange behaviour 奇怪的行为

If i changed the order of the elements then the offset and limit are getting populated. 如果我更改了元素的顺序,则将填充偏移量和限制。 below is request that is getting serialized correctly 以下是正确序列化的请求

<jobReportCriteria>
  <offset>0</offset>
  <limit>25</limit>
  <groupBy>State</groupBy>
  <timePeriod>
    <from>2014-02-06T00:00:00</from>
    <to>2014-05-06T00:00:00</to>
  </timePeriod>
  <queryString>[nationwide]: &quot; nationwide &quot;</queryString>
  <includeTotalClassifiedPostings>true</includeTotalClassifiedPostings>
  <includeTotalUnclassifiedPostings>true</includeTotalUnclassifiedPostings>
  <includeLastDataDate>true</includeLastDataDate>
</jobReportCriteria>

Putting offset and limit at the start somehow enables the serialization. 将偏移量和限制放在开始位置可以启用序列化。 The problem is i cant ask the client to frame the request in specific order. 问题是我不能要求客户端按特定顺序来构造请求。

Can someone let me know what exactly going on here? 有人可以让我知道这里到底发生了什么吗?

Update: 更新:

On further analysis i came to know that order of the data members influence the Serialization but still i think i have ordered my members accordingly and given offset and limit values a maximum order so that it always comes below other parameters. 经过进一步的分析,我知道数据成员的顺序会影响序列化,但我仍然认为我已相应地对我的成员进行了排序,并为offset和limit赋予了最大顺序,以便它始终低于其他参数。 but still it comes as null 但它仍然为空

The order in which DataContractSerializer requires elements to be encountered is spelled out here: Data Member Order : 此处阐明了DataContractSerializer要求遇到元素的顺序: 数据成员顺序

The basic rules for data ordering include: 数据排序的基本规则包括:

  • If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order. 如果数据协定类型是继承层次结构的一部分,则其基本类型的数据成员始终按顺序排列。

  • Next in order are the current type's data members that do not have the Order property of the DataMemberAttribute attribute set, in alphabetical order. 接下来的是当前类型的数据成员,这些成员没有按字母顺序设置DataMemberAttribute属性的Order属性。

  • Next are any data members that have the Order property of the DataMemberAttribute attribute set. 接下来是设置了DataMemberAttribute属性的Order属性的所有数据成员。 These are ordered by the value of the Order property first and then alphabetically if there is more than one member of a certain Order value. 这些按先后按Order属性的值排序,如果某个Order值中有多个成员,则按字母顺序排序。 Order values may be skipped. 订单值可能会被跳过。

Alphabetical order is established by calling the CompareOrdinal method. 通过调用CompareOrdinal方法来建立字母顺序。

Ie, base class data members (ie offset and limit of Criteria ) must needs appear before derived class data members. 即,必须在派生类数据成员之前出现基类数据成员(即Criteria offsetlimit )。

So, here are some possibilities to work around this rule: 因此,有一些方法可以解决此规则:

  1. Modify your class design and flatten your class hierarchy. 修改您的班级设计并展平您的班级层次结构。 Obviously not ideal, but you could do it by replacing a class hierarchy with an interface hierarchy implemented by flat classes. 显然这并不理想,但是您可以通过用平面类实现的接口层次结构替换类层次结构来实现。

  2. Use a data contract surrogate to convert your derived class into a flat proxy surrogate for serialization. 使用数据合同代理将派生类转换为平面代理代理以进行序列化。

  3. Contact your client and get their servicemodel metadata . 联系您的客户并获取他们的服务模型元数据 This will specify the order of fields and will allow c# classes to be automatically generated . 这将指定字段的顺序,并允许自动生成 c#类。

  4. Consider switching to XMLSerializer . 考虑切换到XMLSerializer Documentation here . 文档在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM