【问题标题】:Serialization Failed for application/xml in WebapiWebapi 中的应用程序/xml 序列化失败
【发布时间】:2017-07-31 23:11:57
【问题描述】:

我已更新问题,请参阅更新 1

当我的 WebAPI 尝试以 XML 格式返回数据时出现错误。 JSON 格式可以正常工作。

错误详情:

“ObjectContent`1”类型未能序列化内容类型的响应正文

'应用程序/xml;字符集=utf-8 '。

  • 详细错误::

Type 'Newtonsoft.Json.Linq.JToken' 是一个不支持的递归集合数据合约。考虑修改集合“Newtonsoft.Json.Linq.JToken”的定义以删除对自身的引用。

我以某种方式理解这是由于从 Json.Net 发送反序列化的对象作为结果,

return (JsonConvert.DeserializeObject(JsonString, new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore

            }));

这里的问题是我不能再创建一个模型类,因为结果将根据用户字段选择是动态的(我已经在使用一个模型类)将结果发送给用户。

我们希望同时支持 XML 和 JSON 格式,并且已经尝试了 StackOverflow 中提到的大部分解决方案。任何帮助将不胜感激。

更新 1

我已尝试实施链接中提到的解决方案

Circular reference exception when serializing an object containing a JToken to XML in Web API

仍然显示相同的错误。

为了确保我在做正确的事情,我在这里发布代码。

我在这里获取 Jobject。

        object test = JsonHandling.generateResultSet<IEnumerable<Mytype>>
        (reader,"dsfw");

这是在做什么:

    public static object generateResultSet<T>(T resultList, string s)
    {
        try
        {
            string JsonString = JsonConvert.SerializeObject(resultList, new JsonSerializerSettings
            {
                // Formatting=Formatting.Indented,
                NullValueHandling = NullValueHandling.Ignore,
            });

            // return (JsonHelper.Deserialize(JsonString));

            return (JsonConvert.DeserializeObject(JsonString, new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore

            }));
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

这是我的最终结果集类发布解决方案中提到的修改

public class PagedResults<T>
{
    /// <summary>
    /// The page number this page represents.
    /// </summary>
    /// 
    public int? OffSet { get; set; }

    /// <summary>
    /// The size of this page.
    /// </summary>
    public int? Limit { get; set; }

  //  /// <summary>
  //  /// The total number of pages available.
  //  /// </summary>
  //// public int TotalNumberOfPages { get; set; }

    /// <summary>
    /// The total number of records available.
    /// </summary>
    public int TotalNumberOfRecords { get; set; }

    /// <summary>
    /// The URL to the next page - if null, there are no more pages.
    /// </summary>
    public string NextPageUrl { get; set; }

    /// <summary>
    /// The URL to the Previous page - if null, there are no more pages.
    /// </summary>
    public string PrevPageUrl { get; set; }

    /// <summary>
    /// The URL to the Current page page - if null, there are no more pages.
    /// </summary>
    public string CurrentPageUrl { get; set; }

    /// <summary>
    /// The records this page represents.
    /// </summary>
    [XmlIgnore]
    [JsonProperty]
    public object Results { get; set; }

    [XmlAnyElement("Results")]
    [JsonIgnore]
    public XElement ResultsXml
    {
        get
        {
            return JsonExtensions.SerializeExtraDataXElement("Results", Results);
        }
        set
        {
            Results = JsonExtensions.DeserializeExtraDataXElement("Results", value);
        }
    }
    /// <summary>
    /// This Method creates the paged result set 
    /// </summary>
    /// <typeparam name="TReturn">Type of the model class that has been passed</typeparam>
    /// <param name="results">Reults returned by the DB</param>
    /// <param name="offset">Rows to offset </param>
    /// <param name="limit">Total number of the rows</param>
    /// <param name="req">HTTPrequest obejct </param>
    /// <param name="routeName">The Name of the rouote from the route collections</param>
    /// <returns></returns>
    public PagedResults<TReturn> CreatePagedResults<TReturn>(object results,int? offset,int? limit,HttpRequestMessage req,string routeName)
    {
        try
        {
            var skipAmount = offset;
            var totalNumberOfRecords = 1000;
            var urlHelper = new UrlHelper(req);
            var prevLink = offset > 0 ? urlHelper.Link(routeName, new { offset = offset - 1, limit = limit }) : "";
            var nextLink = (offset + limit) < totalNumberOfRecords - 1 ? urlHelper.Link(routeName, new { offset = offset + limit, limit = limit }) : "";
            var currLink = urlHelper.Link(routeName, new { offset = offset, limit = limit });
            return new PagedResults<TReturn>
            {
                Results = results,
                OffSet = offset,
                Limit = limit,
                TotalNumberOfRecords = totalNumberOfRecords,
                NextPageUrl = nextLink,
                PrevPageUrl = prevLink,
                CurrentPageUrl = currLink
            };
        }
        catch(Exception ex)
        {
            throw ex;
        }
    }
}

如果我评论

       Results = results It works but thats what want to include in result.

最终回归:

PagedResults<MyType> result = new PagedResults<MyType>();
      result = result.CreatePagedResults<MyType>(test, offset, limit, 
Request, "jkewgfewg");
         return Ok(result);

我已经添加了那里提到的 JsonExtensions

【问题讨论】:

  • 错误消息来自 newtonsoft.json 但您的抱怨是您的 xml 格式不正确?这对我来说似乎不匹配;你用的是json还是xml?您的查询是否缺少一些有助于我们解决的细节?
  • 你从哪里得到 JsonString?
  • @BrianRogers :我正在从我的模型对象中获取 Json 字符串。使用 Newtonsoft 的原因是忽略包含 null 的列。 string JsonString = JsonConvert.SerializeObject(resultList, new JsonSerializerSettings { // Formatting=Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, });
  • @CaiusJard 当我请求我的格式为 XML 时,错误消息来自 newtonsoft.json。如果您看到它表明“Newtonsoft.Json.Linq.JToken”上有递归引用,这就是它无法将其转换为 XML 的原因。由于我返回要使用的数据的最终返回来自 Newtonsoft.json,因此您在详细错误中看到它。让我知道是否需要进一步澄清

标签: c# json xml asp.net-web-api json.net


【解决方案1】:

Circular reference exception when serializing an object containing a JToken to XML in Web API 的答案对您不起作用的原因是您使用的是DataContractSerializer,而该答案对XmlSerializer 有效。您有几个选项可以解决此问题。

首先,您可以按照here 的说明全局切换到XmlSerializer,或者按照here 的说明切换到特定的控制器,或者按照herehere 的说明切换到特定的响应。

其次,您可以使用data contract attributes 注释您的PagedResults&lt;T&gt;,以确保JObject-valued 属性未序列化:

[DataContract]
public class PagedResults<T>
{
    /// <summary>
    /// The page number this page represents.
    /// </summary>
    /// 
    [DataMember]
    public int? OffSet { get; set; }

    /// <summary>
    /// The size of this page.
    /// </summary>
    [DataMember]
    public int? Limit { get; set; }

    //  /// <summary>
    //  /// The total number of pages available.
    //  /// </summary>
    //// public int TotalNumberOfPages { get; set; }

    /// <summary>
    /// The total number of records available.
    /// </summary>
    [DataMember]
    public int TotalNumberOfRecords { get; set; }

    /// <summary>
    /// The URL to the next page - if null, there are no more pages.
    /// </summary>
    [DataMember]
    public string NextPageUrl { get; set; }

    /// <summary>
    /// The URL to the Previous page - if null, there are no more pages.
    /// </summary>
    [DataMember]
    public string PrevPageUrl { get; set; }

    /// <summary>
    /// The URL to the Current page page - if null, there are no more pages.
    /// </summary>
    [DataMember]
    public string CurrentPageUrl { get; set; }

    /// <summary>
    /// The records this page represents.
    /// </summary>
    [XmlIgnore]
    [IgnoreDataMember]
    [JsonProperty]
    public object Results { get; set; }

    [XmlAnyElement("Results")]
    [DataMember(Name = "Results")]
    [JsonIgnore]
    public XElement ResultsXml
    {
        get
        {
            return JsonExtensions.SerializeExtraDataXElement("Results", Results);
        }
        set
        {
            Results = JsonExtensions.DeserializeExtraDataXElement("Results", value);
        }
    }
}

但是,此实现存在一个问题,因为DataContractSerializer 不支持与[XmlAnyElement] 完全相同的功能,正如here 所解释的那样。使用此序列化程序序列化为 XML 将引入额外级别的 XML 元素嵌套,这在使用 XmlSerializer(或 Json.NET)时不存在。例如,考虑以下MyType 的定义:

public class MyType
{
    public string Foo { get; set; }
    public string Bar { get; set; }
}

用每个序列化器序列化 PagedResult&lt;MyType&gt; 会产生以下结果:

  • Json.NET:

    {    
      "OffSet": 0,
      "Limit": 1000,
      "TotalNumberOfRecords": 1000,
      "NextPageUrl": "next link",
      "PrevPageUrl": "prev link",
      "CurrentPageUrl": "curr link",
      "Results": {
        "Foo": "Foo Value",
        "Bar": "Bar Value"
      }
    }
    
  • XmlSerializer:

    <PagedResultsOfMyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <OffSet>0</OffSet>
      <Limit>1000</Limit>
      <TotalNumberOfRecords>1000</TotalNumberOfRecords>
      <NextPageUrl>next link</NextPageUrl>
      <PrevPageUrl>prev link</PrevPageUrl>
      <CurrentPageUrl>curr link</CurrentPageUrl>
      <Results>
        <Foo>Foo Value</Foo>
        <Bar>Bar Value</Bar>
      </Results>
    </PagedResultsOfMyType>
    
  • DataContractSerializer:

    <PagedResultsOfMyType5vmUPXwL xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Question45426622">
      <CurrentPageUrl>curr link</CurrentPageUrl>
      <Limit>1000</Limit>
      <NextPageUrl>next link</NextPageUrl>
      <OffSet>0</OffSet>
      <PrevPageUrl>prev link</PrevPageUrl>
      <Results>
        <!--Notice the nested extra <Results> node below -->
        <Results xmlns="">
          <Foo>Foo Value</Foo>
          <Bar>Bar Value</Bar>
        </Results>
      </Results>
      <TotalNumberOfRecords>1000</TotalNumberOfRecords>
    </PagedResultsOfMyType5vmUPXwL>
    

注意到&lt;Results&gt; 节点的嵌套添加级别了吗? DataContractSerializer 无法避免这种情况,除非您为整个 PagedResult&lt;T&gt; 对象手动实现 IXmlSerializer,我不建议这样做,因为它很难正确执行。

【讨论】:

  • 感谢您的详细解释。这实际上是我很多,并且 XMLserliazer 工作。这就是我一直在寻找的。​​span>
猜你喜欢
  • 2021-12-09
  • 1970-01-01
  • 2012-12-26
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多