32

我正在使用 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
    }
});

这是提琴手请求/响应的保存。如您所见,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 格式化程序。

更新:我想通了——在下面查看我自己的答案

4

7 回答 7

42

我想到了!

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

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

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

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

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

于 2012-08-03T23:00:49.080 回答
14

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

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

于 2013-07-17T14:06:32.503 回答
12

该线程中的当前答案已经说明了很多原因,但总结一下,XmlSerializer 仅支持有限数量的类型。

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

如果它没有根据接受标头找到任何匹配项,那么它会选择第一个可以序列化类型的匹配项,在本例中是 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

于 2012-08-04T05:14:57.617 回答
6

答案已经提供,但我想我会把我的发现放在后面,以便对以后来的人有所帮助。

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

我用了

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

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

然后我将 IEnumerable 更改为 List 并且效果很好。看起来 Web API 中的 XML 格式化程序无法处理返回对象中的 IEnumerable。

希望这可以帮助。

于 2014-09-02T00:09:57.530 回答
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()
    {
    }

}
于 2017-08-02T15:03:49.700 回答
0

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

于 2015-05-13T02:50:12.600 回答
0

我只想添加一个可能发生这种情况的原因,即具有内部获取或设置的属性。当您通过按 Ctrl- 向类添加属性时由​​ VS 生成的类型。

public string Foo {get; internal set;}

于 2017-02-09T19:40:40.803 回答