即使使用正确的Accepts标头,WebAPI也不会返回XML

Inf*_*oop 31 asp.net asp.net-web-api

我正在使用ASP.NET WebAPI RC,并托管一个没有任何花哨的API控制器.使用JSON一切正常,但我正在测试使用Accepts标头请求不同的格式,这就是我遇到麻烦的地方.

我正在使用jQuery发出AJAX请求,并设置请求的'dataType'参数.这将正确设置相应的Accept标头,如下所示.

$.ajax({
    type: method,
    url: url,
    dataType: "xml",
    data: data || null,
    success: function (data) {
        // omitted
    }
});
Run Code Online (Sandbox Code Playgroud)

这是fiddler请求/响应的保存.正如您所见,Accept标头显示了application/xml,但WebAPI返回了JSON.我也尝试手动将Accept标头设置为"application/xml"(因此它也没有text/html的东西),但无济于事.

我错过了什么?(注意:我已经在数据中剪断了一些机密信息,但没有对其进行调整)

GET http://localhost/insp**snip**6716 HTTP/1.1
Host: localhost
Connection: keep-alive
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.60 Safari/537.1
Accept: application/xml, text/xml, */*; q=0.01
Referer: http://localhost/inspector/api/test?
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: m=34e2:|2c69:t|47ba:t|4e99:t; .INSPECTOR3COOKIE=08BA683091E2A457B1832E9B*snip*F911D9ED97076


HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Fri, 03 Aug 2012 22:27:42 GMT
Content-Length: 1816

{"Id":2416716,"ProjectId":36,"Url":"http://ins *snip, but obviously this is JSON not XML *
Run Code Online (Sandbox Code Playgroud)

我想指出我没有调整AppStart中的任何格式化程序或任何东西,所以据我所知,默认情况下应该启用JSON和XML格式化程序.

更新:我想通了 - 检查我自己的答案如下

Inf*_*oop 41

我想到了!

我在AppStart中有这个,因为我想要Xml序列化程序而不是DataContract序列化程序:

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
Run Code Online (Sandbox Code Playgroud)

但是......显然我的模型有一些东西让Xml Serializer认为它不能序列化它.我猜这是导致WebAPI决定使用JSON格式化程序.

完全不直观的是,这种无害的外观设置实际上可能会影响使用哪种格式化程序.希望WebAPI的人看到这个:)

某种工具可以让您了解内容协商过程的输入和输出,这样您就可以调试这样的问题.

  • 设置TraceWriter,您将看到许多关于连接机制如何工作的调试信息.详情请见http://www.asp.net/web-api/overview/testing-and-debugging/tracing-in-aspnet-web-api (3认同)
  • 如果对象图中有一个循环,则XmlSerializer将无法处理它.此外,TimeSpans也不受支持. (3认同)
  • 你是对的,这正是似乎正在发生的事情.有一个具有RunNegotiation方法的System.Net.Http.Formatting.DefaultContentNegotiator类.该方法基本上只是循环遍历所有格式化程序并检查它们是否可以处理请求.因此,如果XmlFormatter由于某种原因无法将模型序列化为输出流 - 它将被跳过,并且会考虑下一个Formatter - JSON,它恰好能够序列化您的模型. (2认同)

Kev*_*ady 13

我有同样的问题,但通过向我返回的所有模型添加默认构造函数来修复它.

XML序列化程序创建空白模型对象,然后通过属性上的setter填充它.如果setter受保护或私有,那么该属性也不会被序列化


小智 12

此线程中的当前答案已经提出了很多原因,但总结一下,XmlSerializer只支持有限数量的类型.

在查找"最佳"格式化程序时,正如AASoft正确描述的,DefaultContentNegotiator会询问每个格式化程序是否可以支持特定类型.然后,它将这些格式化程序与请求中的接受标头进行匹配.

如果它没有根据accept标头找到任何匹配,那么它会选择第一个可以序列化类型的匹配项,在本例中是JSON格式化程序.但是,您可以配置DefaultContentNegotiator而不是返回默认格式,然后返回406 None Accepted状态代码.这向客户端指示不能找到匹配的表示,而不是发送客户端可能无法使用的数据,而是生成错误响应.

设置此选项的内容在"内容协商改进"部分的博客"ASP.NET Web API更新 - 5月14日"[1]中进行了描述.

希望这可以帮助,

亨里克

[1] http://blogs.msdn.com/b/henrikn/archive/2012/05/14/asp-net-web-api-updates-may-14.aspx

  • 这将在添加`GlobalConfiguration.Configuration.Services.Replace(typeof(IContentNegotiator),new DefaultContentNegotiator(true))时重新开始; `到你的Application_start. (3认同)

小智 5

答案已经提供,但我认为我会把我的发现放在一起,这样对以后来的人来说可能会有所帮助.

罪魁祸首是IEnumerable.例如,返回包含IEnumerable的类Album的对象并且永远不会获得XML返回 - 仅JSON.

我用了

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true; 
Run Code Online (Sandbox Code Playgroud)

在Global.asax中也是如此.这对于xml返回实际上是必需的.我仍然没有得到XML.

然后我将IEnumerable更改为List,它工作正常.看起来Web API中的XML Formatter无法处理返回对象中的IEnumerable.

希望这可以帮助.