Asp.net WebAPI即使具有正确的Accepts标头也不返回XML
我正在使用ASP.NETWebAPIRC,并托管一个API控制器,对它一点也不感兴趣。JSON的一切都很好,但我正在使用Accepts头测试请求不同的格式,这就是我遇到的问题 我使用jQuery发出AJAX请求,并设置请求的“dataType”参数。这将正确设置适当的Accept标头,如下所示Asp.net WebAPI即使具有正确的Accepts标头也不返回XML,asp.net,asp.net-web-api,Asp.net,Asp.net Web Api,我正在使用ASP.NETWebAPIRC,并托管一个API控制器,对它一点也不感兴趣。JSON的一切都很好,但我正在使用Accepts头测试请求不同的格式,这就是我遇到的问题 我使用jQuery发出AJAX请求,并设置请求的“dataType”参数。这将正确设置适当的Accept标头,如下所示 $.ajax({ type: method, url: url, dataType: "xml", data: data || null, success: fun
$.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内容),但没有效果
我到底错过了什么?(注意:我在数据中截取了一些机密信息,但没有进行其他调整)
我想指出的是,我没有在AppStart或任何东西中调整任何格式化程序,据我所知,默认情况下应该启用JSON和XML格式化程序
更新:我想出来了——检查下面我自己的答案我想出来了
我在AppStart中使用了这个,因为我想要的是Xml序列化程序,而不是DataContract序列化程序:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
然而。。。显然,我的模型中有某种东西使Xml序列化程序认为它无法序列化它。我猜这导致WebAPI决定改用JSON格式化程序
这种看起来无害的设置实际上可能会影响所使用的格式化程序,这完全是不直观的。希望WebAPI的人看到这一点:)
某种工具可以让您了解内容协商过程的输入和输出,这样您就可以调试类似的问题了。此线程中当前的答案已经给出了很多原因,但简单地说,XmlSerializer只支持有限的类型 在寻找“最佳”格式化程序时,正如AASoft所正确描述的那样,DefaultContentCongregator会询问每个格式化程序是否可以支持特定类型。然后,它将这些格式化程序与请求中的accept头进行匹配 如果它没有找到任何基于accept头的匹配项,那么它会选择第一个可以序列化类型的,在本例中是JSON格式化程序。但是,您可以将DefaultContentCongregator配置为,而不是返回默认格式,然后返回406 None Accepted状态代码。这向客户端指示找不到匹配的表示,而不是发送客户端可能无法使用的数据,它会生成错误响应 设置此选项在博客“ASP.NET Web API更新–5月14日”[1]的“内容协商改进”一节中进行了说明 希望这有帮助 亨里克
[1] 我也遇到了同样的问题,但通过向我返回的所有模型中添加默认构造函数,解决了这个问题
XML序列化程序创建空白模型对象,然后通过属性上的setter填充它。如果setter是受保护的或私有的,那么该属性也不会被序列化。答案已经给出,但我想我会把我的发现放在这里,以便对以后的任何人都有帮助 罪犯数不胜数。例如,返回包含IEnumerable的类Album的对象,而从不获取XML返回仅JSON 我曾经
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
在Global.asax中也是如此。这实际上是xml返回所必需的。但我还是没有找回XML
然后我将IEnumerable更改为List,它工作得很好。看起来Web API中的XML格式化程序无法处理返回对象中的IEnumerable
希望这能有所帮助。对于任何要序列化的属性,请小心使用可为null的int。设置为
config.Formatters.XmlFormatter.UseXmlSerializer=true
的可为空int将导致Web API返回JSON,无论您的accept头说什么我只想再添加一个可能发生这种情况的原因,即具有内部get或set的属性。当您通过按Ctrl-向类添加属性时,VS生成的类型
就像
公共字符串Foo{get;internal set;}
一样,这也是本文的后续内容。当我们在返回模型中有一个对象列表,但列表中的对象没有无参数构造函数时,我们遇到了这个问题。我们的代码如下所示:
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;
}
}
公共类返回类
{
公共int值{get;set;}
公共物品列表{get;set;}
}
公共类其他类
{
public int OtherValue{get;set;}
公共OtherClass(OtherObject o)
{
this.OtherValue=o.OtherValue;
}
}
我们只需为子类对象添加一个无参数构造函数
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()
{
}
}
公共类返回类
{
公共int值{get;set;}
公共物品列表{get;set;}
}
公共类其他类
{
public int OtherValue{get;set;}
公共OtherClass(OtherObject o)
{
this.OtherValue=o.OtherValue;
}
公共类()
{
}
}
你说得对,这正是发生的事情。有一个System.Net.Http.Formatting.DefaultContentCongregator类具有RunNegotiation方法。该方法基本上只是循环遍历所有格式化程序并检查它们是否能够处理请求。因此,如果XmlFormatter由于某种原因无法将您的模型序列化到输出流,则会跳过它,并考虑下一个格式化程序-JSON,它恰好能够序列化您的模型。设置TraceWriter,您将看到大量有关conneg机制如何工作的调试信息。请参阅此处的详细信息如果在对象图中有一个循环,则XmlSerializer将无法处理它。也不支持时间跨度。您可以编写一个直接在模型上调用内容协商的测试,以确保它正确序列化。另外,在最新的Web API源代码中
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()
{
}
}