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

时间:2012-08-03 22:50:03

标签: 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
    }
});

这是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 *

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

更新:我想出来了 - 请查看我自己的答案

7 个答案:

答案 0 :(得分:40)

我明白了!

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

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

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

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

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

答案 1 :(得分:13)

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

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

答案 2 :(得分:12)

这个帖子中的当前答案已经说明了很多原因,但总结一下,XmlSerializer只支持有限数量的类型。

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

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

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

希望这有帮助,

的Henrik

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

答案 3 :(得分:5)

答案已经提供,但我认为我会把我的调查结果放在一起,以便以后来的任何人都有所帮助。

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

我用过

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true; 
也可以在Global.asax中找到

。这对于xml返回实际上是必需的。我仍然没有收回XML。

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

希望这有帮助。

答案 4 :(得分:3)

就像这样的后续行动。当我们在返回模型中有一个对象列表但是列表中的对象没有无参数构造函数时,我们遇到了这个问题。我们的代码看起来像这样:

public class ReturnClass
{
    public int Value { get; set; }

    public List<OtherClass> ListOfThings { get; set; }
}

public class OtherClass 
{
    public int OtherValue { get; set; }

    public OtherClass(OtherObject o) 
    {
       this.OtherValue = o.OtherValue;
    }  
}

我们只需要为SubClass对象添加一个无参数构造函数。

public class ReturnClass
{
    public int Value { get; set; }

    public List<OtherClass> ListOfThings { get; set; }
}

public class OtherClass 
{
    public int OtherValue { get; set; }

    public OtherClass(OtherObject o) 
    {
       this.OtherValue = o.OtherValue;
    }

    public OtherClass()
    {
    }

}

答案 5 :(得分:0)

对于您可能正在序列化的任何属性,请小心使用nullable int。设置为config.Formatters.XmlFormatter.UseXmlSerializer = true的可空int将导致Web API返回JSON,无论您的接受标头是什么

答案 6 :(得分:0)

我只想添加一个可能发生这种情况的原因,即内部获取或设置的属性。当您通过按Ctrl - 。

向类添加属性时由​​VS生成的类型

喜欢public string Foo {get; internal set;}