如何让ASP.NETWeb API使用Chrome返回JSON而不是XML?

使用较新的ASP.NETWeb API,在Chrome中我看到了XML-我如何将其更改为请求JSON以便我可以在浏览器中查看它?我相信它只是请求标头的一部分,我是正确的吗?

948699 次浏览

看看WebAPI中的内容协商。这些(第一部分第二部分)非常详细和全面的博客文章解释了它是如何工作的。

简而言之,你是对的,只需要设置AcceptContent-Type请求标头。鉴于您的Action未编码为返回特定格式,您可以设置Accept: application/json

一种快速选择是使用MediaTypeMping特化。这是在Application_Start事件中使用QueryStringMping的示例:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("a", "b", "application/json"));

现在,每当url包含查询字符串?在这种情况下,Json响应将显示在浏览器中。

我发现Chrome应用程序“Advanced REST Client”非常适合使用REST服务。您可以将Content-Type设置为application/json等:高级REST客户端

MVC4快速提示#3-从ASP. Net Web API中删除XML格式

Global.asax中添加行:

GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

像这样:

protected void Application_Start(){AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();}

Global.asax中,我使用下面的代码。我获取JSON的URI是http://www.digantakumar.com/api/values?json=true

protected void Application_Start(){AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);RouteConfig.RegisterRoutes(RouteTable.Routes);BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new  QueryStringMapping("json", "true", "application/json"));}

不要使用您的浏览器来测试您的API。

相反,尝试使用允许您指定请求的HTTP客户端,例如CURL,甚至Fiddler。

此问题的问题在于客户端,而不是API。根据浏览器的请求,Web API的行为正确。

如果您在WebApiConfig中这样做,默认情况下您将获得JSON,但如果您将text/xml作为请求Accept标头传递,它仍然允许您返回XML。

注意:这删除了对application/xml的支持

public static class WebApiConfig{public static void Register(HttpConfiguration config){config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);}}

如果您不使用MVC项目类型,因此一开始就没有这个类,请看到这个答案了解有关如何合并它的详细信息。

注意:阅读此答案的注释,如果您使用WebAPI的默认错误处理,它可能会产生XSS漏洞

我只是在我的MVC网页应用程序接口项目的App_Start / WebApiConfig.cs类中添加以下内容。

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html") );

这确保您在大多数查询中获得JSON,但当您发送text/xml时,您可以获得XML

如果您需要将响应Content-Type作为application/json,请选中托德的答案在下面

NameSpace正在使用System.Net.Http.Headers

WebApiConfig.cs中,在注册函数的末尾添加:

// Remove the XML formatterconfig.Formatters.Remove(config.Formatters.XmlFormatter);

来源

User-Agent标头包含“Chrome”时,我使用全局操作过滤器删除Accept: application/xml

internal class RemoveXmlForGoogleChromeFilter : IActionFilter{public bool AllowMultiple{get { return false; }}
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext,CancellationToken cancellationToken,Func<Task<HttpResponseMessage>> continuation){var userAgent = actionContext.Request.Headers.UserAgent.ToString();if (userAgent.Contains("Chrome")){var acceptHeaders = actionContext.Request.Headers.Accept;var header =acceptHeaders.SingleOrDefault(x => x.MediaType.Contains("application/xml"));acceptHeaders.Remove(header);}
return await continuation();}}

似乎奏效了。

这段代码使json成为我的默认设置,并允许我也使用XML格式。我将只附加xml=true

GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "application/xml"));GlobalConfiguration.Configuration.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

谢谢大家!

由于问题是Chrome特定的,您可以获得邮递员扩展,它允许您设置请求内容类型。

邮递员

我最喜欢Felipe Leusin的方法——确保浏览器在不影响实际需要XML的客户端的内容协商的情况下获得JSON。对我来说,唯一缺少的是响应标头仍然包含内容类型:text/html。为什么会出现这个问题?因为我使用JSON格式Chrome扩展来检查内容类型,而且我没有得到我习惯的漂亮格式。我用一个简单的自定义格式化程序修复了这个问题,该格式化程序接受text/html请求并返回应用程序/json响应:

public class BrowserJsonFormatter : JsonMediaTypeFormatter{public BrowserJsonFormatter() {this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));this.SerializerSettings.Formatting = Formatting.Indented;}
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) {base.SetDefaultContentHeaders(type, headers, mediaType);headers.ContentType = new MediaTypeHeaderValue("application/json");}}

像这样注册:

config.Formatters.Add(new BrowserJsonFormatter());

使用请求头映射效果更好,因为它还在响应标头中设置了Content-Type = application/json,这允许Firefox(使用JSONView插件)将响应格式化为JSON。

GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(new System.Net.Http.Formatting.RequestHeaderMapping("Accept","text/html",StringComparison.InvariantCultureIgnoreCase,true,"application/json"));

MSDN使用ASP.NET和AngularJS构建单页应用程序(约41分钟)。

public static class WebApiConfig{public static void Register(HttpConfiguration config){// ... possible routing etc.
// Setup to return json and camelcase it!var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;formatter.SerializerSettings.ContractResolver =new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();}

它应该是当前的,我试过了,它奏效了。

我不清楚为什么答案如此复杂。当然,有很多方法可以做到这一点,使用QueryStrings、标头和选项……但我认为最好的做法很简单。你请求一个普通的URL(例如:http://yourstartup.com/api/cars),作为回报,你得到JSON。你得到带有正确响应标头的JSON:

Content-Type: application/json

在寻找这个问题的答案时,我找到了这个线索,并且不得不继续下去,因为这个公认的答案并不完全有效。我确实找到了一个答案,我觉得它太简单了,不是最好的答案:

设置默认的WebAPI格式化程序

我也会在这里加上我的建议。

WebApiConfig.cs
namespace com.yourstartup{using ...;using System.Net.Http.Formatting;...config.Formatters.Clear(); //because there are defaults of XML..config.Formatters.Add(new JsonMediaTypeFormatter());}

我确实有一个关于默认值(至少我看到的那些)来自哪里的问题。它们是. NET默认值,还是可能在其他地方创建的(由我的项目中的其他人创建的)。总之,希望这能有所帮助。

自从提出(并回答)这个问题以来已经过去了一段时间,但另一种选择是在请求处理期间使用MessageHandler覆盖服务器上的Accept标头,如下所示:

public class ForceableContentTypeDelegationHandler : DelegatingHandler{protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken){var someOtherCondition = false;var accHeader = request.Headers.GetValues("Accept").FirstOrDefault();if (someOtherCondition && accHeader.Contains("application/xml")){request.Headers.Remove("Accept");request.Headers.Add("Accept", "application/json");}return await base.SendAsync(request, cancellationToken);}}

其中someOtherCondition可以是任何内容,包括浏览器类型等。这适用于有条件的情况,我们有时只想覆盖默认的内容协商。否则,根据其他答案,您只需从配置中删除不必要的格式化程序。

当然,您需要注册它。您可以在全球范围内执行此操作:

  public static void Register(HttpConfiguration config) {config.MessageHandlers.Add(new ForceableContentTypeDelegationHandler());}

或按路线划分:

config.Routes.MapHttpRoute(name: "SpecialContentRoute",routeTemplate: "api/someUrlThatNeedsSpecialTreatment/{id}",defaults: new { controller = "SpecialTreatment" id = RouteParameter.Optional },constraints: null,handler: new ForceableContentTypeDelegationHandler());

由于这是一个消息处理程序,它将像HttpModule一样在管道的请求和响应端运行。因此,您可以使用自定义标头轻松确认覆盖:

public class ForceableContentTypeDelegationHandler : DelegatingHandler{protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken){var wasForced = false;var someOtherCondition = false;var accHeader = request.Headers.GetValues("Accept").FirstOrDefault();if (someOtherCondition && accHeader.Contains("application/xml")){request.Headers.Remove("Accept");request.Headers.Add("Accept", "application/json");wasForced = true;}
var response =  await base.SendAsync(request, cancellationToken);if (wasForced){response.Headers.Add("X-ForcedContent", "We overrode your content prefs, sorry");}return response;}}

这是一个类似于jayson.centeno和其他答案的解决方案,但使用System.Net.Http.Formatting的内置扩展。

public static void Register(HttpConfiguration config){// add support for the 'format' query param// cref: http://blogs.msdn.com/b/hongyes/archive/2012/09/02/support-format-in-asp-net-web-api.aspxconfig.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json");config.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");
// ... additional configuration}

该解决方案主要面向在WebApi的早期版本中支持OData的$格式,但它也适用于非OData实现,并返回Content-Type: application/json; charset=utf-8响应中的标头。

它允许您在使用浏览器进行测试时将&$format=json&$format=xml标记到uri的末尾。当使用非浏览器客户端时,它不会干扰其他预期行为,您可以在其中设置自己的标头。

你只需要像这样改变App_Start/WebApiConfig.cs

public static void Register(HttpConfiguration config){// Web API configuration and services
// Web API routesconfig.MapHttpAttributeRoutes();//Below formatter is used for returning the Json result.var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);//Default routeconfig.Routes.MapHttpRoute(name: "ApiControllerOnly",routeTemplate: "api/{controller}");}

这是我在应用程序中使用的最简单的方法。在Register函数的App_Start\WebApiConfig.cs中添加以下3行代码:

var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));

Asp.netWeb API会自动将返回的对象序列化为JSON,并在标头中添加application/json,以便浏览器或接收者了解您正在返回JSON结果。

WebApiConfig是您可以配置是要以json还是xml输出的地方。默认情况下,它是xml。在寄存器函数中,我们可以使用HttpConfiguration格式来格式化输出。

需要System.Net.Http.Headers => MediaTypeHeaderValue("text/html")才能获得json格式的输出。

输入图片描述

在最新版本的ASP.netWebApi 2中,在WebApiConfig.cs下,这将工作:

config.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);config.Formatters.Add(GlobalConfiguration.Configuration.Formatters.JsonFormatter);

只需将这两行代码添加到您的WebApiConfig类中

public static class WebApiConfig{public static void Register(HttpConfiguration config){//add this two lineconfig.Formatters.Clear();config.Formatters.Add(new JsonMediaTypeFormatter());

............................}}

返回正确的格式由媒体类型格式化程序完成。正如其他人提到的,您可以在WebApiConfig类中执行此操作:

public static class WebApiConfig{public static void Register(HttpConfiguration config){...
// Configure Web API to return JSONconfig.Formatters.JsonFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
...}}

有关更多信息,请检查:

如果您的操作返回XML(默认情况下是这样),并且您只需要一个特定的方法来返回JSON,那么您可以使用ActionFilterAttribute并将其应用于该特定操作。

过滤器属性:

public class JsonOutputAttribute : ActionFilterAttribute{public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext){ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;var value = content.Value;Type targetType = actionExecutedContext.Response.Content.GetType().GetGenericArguments()[0];
var httpResponseMsg = new HttpResponseMessage{StatusCode = HttpStatusCode.OK,RequestMessage = actionExecutedContext.Request,Content = new ObjectContent(targetType, value, new JsonMediaTypeFormatter(), (string)null)};
actionExecutedContext.Response = httpResponseMsg;base.OnActionExecuted(actionExecutedContext);}}

适用于行动:

[JsonOutput]public IEnumerable<Person> GetPersons(){return _repository.AllPersons(); // the returned output will be in JSON}

请注意,您可以在动作装饰上省略单词Attribute,仅使用[JsonOutput]而不是[JsonOutputAttribute]

上面的大多数答案都很有道理。由于您看到数据被格式化为XML格式,这意味着应用了XML格式化程序,因此您可以通过从HttpConfiguration参数中删除XMLFor的内容来查看JSON格式,例如

public static void Register(HttpConfiguration config){config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "{controller}/{id}",defaults: new { id = RouteParameter.Optional });config.Formatters.Remove(config.Formatters.XmlFormatter);config.EnableSystemDiagnosticsTracing();}

因为JSON是默认格式

config.Formatters.Remove(config.Formatters.XmlFormatter);

我很惊讶地看到这么多回复需要编码来更改一个 API中的单个用例(GET),而不是使用必须安装一次并可用于任何 API(自己或第三方)和所有用例的适当工具。

所以好的答案是:

  1. 如果您只想请求json或其他内容类型,请安装请求或类似工具并修改Accept标头。
  2. 如果您也想使用POST并且格式良好的json、xml等,请使用适当的API测试扩展,如邮递员ARC

您可以使用如下:

GlobalConfiguration.Configuration.Formatters.Clear();GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

多年来一直使用FelipeLeusin的答案,在最近更新核心库和Json. Net之后,我遇到了System.MissingMethodException:支持的MediaTypes。在我的情况下,希望对遇到同样意外异常的其他人有所帮助的解决方案是安装System.Net.Http。NuGet显然在某些情况下会删除它。手动安装后,问题得到解决。