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

How do I get ASP.NET Web API to return JSON instead of XML using Chrome?

使用更新的ASP.NET Web API,在Chrome中,我看到的是XML——如何将其更改为请求JSON,以便在浏览器中查看它?我相信这只是请求头的一部分,我说的对吗?


我只是在我的MVC Web API项目中的App_Start / WebApiConfig.cs类中添加了以下内容。

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

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

如果您需要将Content-Type回复为application/json,请查看下面的todd答案。

NameSpace使用System.Net.Http.Headers


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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项目类型,因此没有这个类作为开始,请参阅这个答案,以了解有关如何合并它的详细信息。


我最喜欢Felipe Leucin的方法——确保浏览器获得JSON,而不影响真正需要XML的客户机的内容协商。我唯一缺少的是响应头仍然包含内容类型:text/html。为什么会有问题?因为我使用了JSON格式化程序chrome扩展,它检查内容类型,而且我没有得到我习惯的格式。我用一个简单的自定义格式化程序修复了这个问题,它接受文本/HTML请求并返回application/json响应:

1
2
3
4
5
6
7
8
9
10
11
12
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");
    }
}

这样注册:

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


使用requestheadermapping的效果更好,因为它还将响应头中的Content-Type = application/json设置为允许firefox(带有jsonview插件)将响应格式化为json。

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


MVC4快速提示3–从ASP.NET Web API中删除XML格式化程序

Global.asax中,添加行:

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

像这样:

1
2
3
4
5
6
7
8
9
10
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    BundleTable.Bundles.RegisterTemplateBundles();
    GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
}


在webapiconfig.cs中,添加到register函数的末尾:

1
2
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);

来源。


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

1
2
3
4
5
6
7
8
9
10
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"));
}


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

简而言之,您是对的,只需要设置AcceptContent-Type请求头。如果您的操作没有被编码为返回特定的格式,那么您可以设置Accept: application/json


由于这个问题是特定于chrome的,所以您可以获得postman扩展,它允许您设置请求内容类型。

Postman


一个快速的选项是使用mediatypemapping专门化。以下是在应用程序启动事件中使用QueryStringMapping的示例:

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

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


这段代码使JSON成为我的默认值,并允许我使用XML格式。我就在后面加上xml=true

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

谢谢大家!


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

相反,尝试使用允许您指定请求的HTTP客户机,例如curl,甚至fiddler。

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


以上大多数答案都是完全合理的。因为您看到的数据是以XML格式格式化的,这意味着应用了XML格式化程序,所以您只需从httpconfiguration参数中删除xml formatter即可看到json格式,如

1
2
3
4
5
6
7
8
9
10
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是默认格式


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();
    }
}

似乎起作用了。


我发现Chrome应用程序"高级REST客户端"非常适合使用REST服务。您可以将内容类型设置为application/json等:高级REST客户端


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

1
2
3
4
5
6
7
8
9
10
11
12
13
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ...

        // Configure Web API to return JSON
        config.Formatters.JsonFormatter
        .SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));

        ...
    }
}

有关更多信息,请查看:

  • ASP.NET Web API 2中的媒体格式化程序。
  • ASP.NET Web API中的内容协商。

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

筛选器属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
    }
}

应用于操作:

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

注意,你可以省略动作装饰上的Attribute一词,只使用[JsonOutput]而不是[JsonOutputAttribute]


我不清楚为什么答案如此复杂。当然,有很多方法可以做到这一点,包括查询字符串、头和选项…但我认为最好的做法很简单。您请求一个普通的URL(例如:http://yourstartup.com/api/cars),作为回报,您将得到json。您将得到带有适当响应头的JSON:

1
Content-Type: application/json

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

设置默认的WebAPI格式化程序

我也在这里加小费。

1
2
3
4
5
6
7
8
9
10
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默认值,还是在其他地方创建的(由我项目中的其他人创建的)。安威,希望这有帮助。


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

1
2
3
4
5
6
7
8
9
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.aspx
    config.Formatters.JsonFormatter.AddQueryStringMapping("$format","json","application/json");
    config.Formatters.XmlFormatter.AddQueryStringMapping("$format","xml","application/xml");

    // ... additional configuration
 }

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

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


根据最新版本的ASP.NET WebAPI 2,

WebApiConfig.cs项下,这是可行的。

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


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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.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 route
        config.Routes.MapHttpRoute(
           name:"ApiControllerOnly",
           routeTemplate:"api/{controller}"
       );
    }


只需在webapiconfig类中添加这两行代码

1
2
3
4
5
6
7
8
9
10
11
12
public static class WebApiConfig
{
     public static void Register(HttpConfiguration config)
     {
          //add this two line
          config.Formatters.Clear();
          config.Formatters.Add(new JsonMediaTypeFormatter());


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

您可以如下使用:

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


自从这个问题被提出(和回答)以来已经过了一段时间,但是另一个选项是在请求处理期间使用下面的消息处理程序重写服务器上的accept头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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可以是任何内容,包括浏览器类型等。这适用于有条件的情况,有时我们只想覆盖默认的内容协商。否则,根据其他答案,您只需从配置中删除不必要的格式化程序。

当然,你需要登记。您可以全局执行此操作:

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

或按路线排列:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
    }
}


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

1
2
3
4
5
    var formatters = GlobalConfiguration.Configuration.Formatters;

    formatters.Remove(formatters.XmlFormatter);

    config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));

ASP.NET Web API将自动将返回的对象序列化到JSON,并且在头中添加了application/json,因此浏览器或接收器将理解您正在返回JSON结果。


从msdn构建一个带有ASP.NET和AngularJS的单页应用程序(大约41分钟)。

1
2
3
4
5
6
7
8
9
10
11
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();
    }

它应该是最新的,我试过了,它起作用了。


在最近更新了核心库和json.net之后,使用Felipe Leucin多年的答案,我遇到了一个System.MissingMethodException:支持的媒体类型。在我的例子中,解决方案是安装System.Net.Http,希望对遇到同样意外异常的其他人有所帮助。在某些情况下,Nuget显然会移除它。手动安装后,问题得到解决。


webapiconfig是一个可以配置以JSON还是XML形式输出的地方。默认情况下,它是XML。在register函数中,我们可以使用httpconfiguration格式化程序来格式化输出。system.net.http.headers=>mediatypeheadervalue("text/html")需要以JSON格式获取输出。enter image description here


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

所以好的答案是:

  • 如果您只想请求JSON或其他内容类型,请安装requestly或类似的工具并修改accept头。
  • 如果您也希望使用Post,并且拥有格式良好的JSON、XML等,请使用适当的API测试扩展,如Postman或Arc。