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


1220

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


8
这里有一个讨论,使仅返回JSON为默认行为:github.com/aspnet/Mvc/issues/1765
Natan

Answers:


1736

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

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

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

如果您需要得到答复Content-Typeapplication/json请检查以下Todd的回答

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


115
这是一个令人惊讶地被忽略的答案,尽管最初的问题还不是很清楚,但这直接使JSON成为Web浏览器(发送Accept:text / html)的默认响应。做得好。
gregmac

16
+1最好的答案。我想有很多人选择完全删除XML,只是因为他们在浏览器中看不到JSON。
Derek Hunziker

3
我发现这样做的时候,第三方提供的带有HTML中断标签的数据最终以回车符结束。JSON然后无效。如果这会影响您,最好使用接受的答案。
Stonetip 2014年

23
请注意,响应的Content-Type标头仍为text/html
Mrchief的

78
这太可怕了。响应内容类型标头应为application / json。此“解决方案”使其为text / html。
meffect 2014年

501

如果您在中执行此操作,则WebApiConfig默认情况下将获取JSON,但如果将其text/xml作为请求Accept标头传递,它仍将允许您返回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项目类型,因此没有此类,那么请参阅此答案以获取有关如何合并它的详细信息。


51
请注意,原始行为是正确的。Chrome请求application/xml的优先级为0.9,*/*优先级为0.8。通过删除,application/xml可以消除Web API在客户端特别要求时返回XML的功能。例如,如果您发送“ Accept:application / xml”,您仍然会收到JSON。
porges

11
是我,还是第一句话不正确?该代码似乎完全删除了XML,而不仅仅是更改默认值。
NickG

6
@NickG:这里忽略的一个解决方案,恕我直言是一个更好的选择(保留应用程序/ xml),是此页下面Felipe Leusin提出的解决方案。使用config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(“ text / html”));
科恩

1
那么,我们如何通过Web配置做到这一点,以便默认情况下获取json并根据需要获取XML?
凯尔

4
@Felipse Leusin在下面的回答实际上更短并且效果更好。
肯·史密斯

313

使用RequestHeaderMapping效果更好,因为它还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"));

6
这是最精简和最简单的解决方案,Fiddler还将检测返回的内容类型为josn。
史蒂夫·约翰逊

4
真好!您会建议将其放在代码的什么位置?
蒂姆·阿贝尔

9
它应该放在WebApiConfig.cs中
Animesh

9
为我工作。我需要添加一个使用System.Net.Http.Formatting;
bbsimonbb '16

1
为方便起见,链接:此答案与我通常执行的另一个设置步骤配合使用:stackoverflow.com/a/28337589/398630
BrainSlugs83

308

我最喜欢Felipe Leusin的方法 -确保浏览器获取JSON,而又不损害来自实际需要XML的客户端的内容协商。对我而言,唯一缺少的是响应头仍然包含content-type:text / html。为什么会有问题呢?因为我使用的是JSON Formatter Chrome扩展程序,它检查内容类型,所以我没有惯用的漂亮格式。我用一个简单的自定义格式化程序修复了该问题,该格式化程序接受文本/ html请求并返回application / 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());

24
在构造函数中添加,this.SerializerSettings.Formatting = Formatting.Indented;如果您希望它的外观漂亮而不带浏览器扩展。
Alastair Maw

10
您为什么要在电线上进行漂亮的打印?
meffect 2014年

8
@ dmit77的答案不是比这个更好(更简洁)吗?
H.Wolper 2014年

8
@eddiegroves您不希望在电线上打印漂亮的文字。您希望服务器通过网络发送最少的位(即:无空格)。然后,您希望浏览器使用插件等很好地格式化它。Javascript通常需要解析JSON,为什么通过引入不必要的格式来使其变慢
meffect 2015年

13
对于谁是寻找Google员工:不要忘了添加using System.Net.Http.Formattingusing Newtonsoft.Json
Berriel

186

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();
}

9
可行-将JSON设置为默认值而不是XML更好。
whitneyland

5
但是您还能返回xml吗?
Thomas Stock

99
我测试了,但是你不能。因此,这将删除XML支持。亲爱的Google人们,请注意
Thomas Stock

3
如果您在下面查看我的答案,这将使XML仍然返回,但是让网站以JSON响应浏览器
Glenn Slaven 2012年

3
@GlennSlaven是的,您的答案应该是标记为正确答案的答案。
radu florescu 2012年

114

WebApiConfig.cs中,添加到Register函数的末尾:

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

来源


XmlFormatter是MVC4中的新功能吗?
Glenn Slaven 2013年

1
在MVC5中,可以通过将config替换为GlobalConfiguration.Configuration来完成
Steven

4
对于仅必须支持JSON并且在任何情况下都不允许发出XML的项目,到目前为止,这是最佳选择。
卢克C

1
config.Formatters.Add(config.Formatters.JsonFormatter);
卡布隆

3
这太可怕了。-即使客户端明确要求在Content-Type标头中要求XML,无论如何都将始终返回JSON。
BrainSlugs83

94

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"));
}


默认情况下,返回哪种数据Web API格式。是json还是webapi?谢谢
托马斯

54

看一下WebAPI中的内容协商。这些(第1部分第2部分)非常详尽详尽的博客文章解释了其工作原理。

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


6
“所以我可以在浏览器中查看它”
Spongman

1
@Spongman,是的,可以。但是请使用诸如REST Client之类的扩展-大多数浏览器都具有类似的扩展名。在浏览器中直接输入url是1。太限制(无法控制标题,不能发布数据等);2.错误-浏览器未使用预期要使用的Web api-您不能依靠它正确地对其进行测试。因此,再次,一个好的REST客户端附加组件将解决此问题。
Ivaylo Slavov

45

由于问题是特定于Chrome的,因此您可以获得Postman扩展程序,该扩展程序可让您设置请求内容类型。

邮差


在Firefox中,只需转到about:config,搜索accept.default并将network.http.accept.default配置内容更改为text/html,application/xhtml+xml,application/json;q=0.9,application/xml;q=0.8,*/*;q=0.7
Bjartur Thorlacius

或更妙的是,只是text/html,application/xhtml+xml;q=1.0,*/*;q=0.7为了避免诸如Bitbucket之类的漏洞主机意外地为您的浏览器JSON代替HTML。
Bjartur Thorlacius


35

一种快速的选择是使用MediaTypeMapping专用化。这是在Application_Start事件中使用QueryStringMapping的示例:

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

现在,在这种情况下,只要网址包含查询字符串?a = b,Json响应都将显示在浏览器中。


2
这非常有用。如果要使用path.to/item.json,也可以使用UriPathExtensionMapping而不是QueryStringMapping
nuzzolilo 2012年

32

此代码将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"));

谢谢大家!


1
这是最灵活的答案(并且现在确实应该是默认配置)。要添加到此答案,JSON是默认值,包括来自浏览器的默认值。要查看XML,请添加查询字符串:?xml = true
raider33

尝试了一些策略。对XML和JSON进行了简单的测试,即开即用
pat capozzi

23

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

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

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


30
为什么不使用浏览器?这是一个显而易见的工具。
安德斯·林登2012年

4
我认为这里的观点是正确且重要的-如果问题是由客户端引起的,则我们不应该为应用程序的工作部分(MVC WebAPI基础结构)加上过多的内容。正确使用Api的实际用例(通过提供正确的标头),这是应用程序的责任。我不同意完全丢弃浏览器-为了进行测试,几乎所有浏览器都有很多工具(类似Rest Client的扩展程序开始)。
Ivaylo Slavov

6
这可能是一条评论。
bonh,2015年

17

以上大多数答案都是很合理的。由于您看到的是以XML格式格式化的数据,这意味着已应用XML格式化程序,因此您只需从HttpConfiguration参数中删除XMLFormatter即可看到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是默认格式


12

Accept: application/xmlUser-Agent标题包含“ Chrome” 时,我使用了全局操作过滤器来删除:

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();
    }
}

似乎可以工作。



10

返回正确的格式由媒体类型格式化程序完成。正如其他人提到的,您可以在WebApiConfig课堂上这样做:

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"));

        ...
    }
}

有关更多信息,请检查:

如果您的操作正在返回XML(默认情况下是这种情况),并且您只需要一种特定的方法来返回JSON,则可以使用an 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]



6

按照最新版本的ASP.net WebApi 2,

在下WebApiConfig.cs,这将工作

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

6

我不清楚为什么答案中会包含所有这些复杂性。当然,可以使用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默认值,还是在其他地方(由我项目中的其他人创建)创建。Anways,希望这会有所帮助。


5

这是一个类似于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.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。使用非浏览器客户端可以在其中设置自己的标头时,它不会干扰其他预期行为。


5

您可以如下使用:

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

如果您要使WebAPI应用程序仅传递JSON消息,请考虑以下答案。
allen1

4

只需在WebApiConfig类 上添加这两行代码

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


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

3

您只需App_Start/WebApiConfig.cs像这样更改:

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}"
       );
    }

删除格式化程序通常不是一个好主意,因为您要删除功能。
naspinski '16

实际上,在这种情况下,它对我来说效果很好,很多其他人也提出了这样的建议。我是从myview.rahulnivi.net/building-spa-angular-mvc-5 书中学到的!
vaheeds,2016年

2

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();
    }

它应该是最新的,我尝试过并且有效。


2

自问(并回答)此问题以来已经过去了一段时间,但是另一种选择是在请求处理期间使用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;
    }
}

2

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

    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结果。


1

WebApiConfig是您可以配置是否要以json或xml输出的地方。默认情况下是xml。在register函数中,我们可以使用HttpConfiguration Formatters格式化输出。需要System.Net.Http.Headers => MediaTypeHeaderValue(“ text / html”)才能获取json格式的输出。 在此处输入图片说明


1

在最近更新核心库和Json.Net之后,使用Felipe Leusin多年的答案,我遇到了System.MissingMethodException:SupportedMediaTypes。就我而言,该解决方案是install,对希望遇到其他意外异常的其他人有所帮助System.Net.Http。NuGet显然在某些情况下将其删除。手动安装后,问题已解决。


-3

令我惊讶的是,有如此多的答复要求通过编码来更改一个 API中的单个用例(GET),而不是使用适当的工具,该工具必须安装一次并可以用于任何 API(自己或第三方),并且所有用例。

因此,好的答案是:

  1. 如果您只想请求json或其他内容类型,请安装Requestly或类似工具并修改Accept标头。
  2. 如果您也想使用POST并格式化好json,xml等格式,请使用适当的API测试扩展程序,例如PostmanARC

有些人喜欢做事而不以多余的工具和库的形式夸大其词。
tno2007

仅由于某人使用了错误的工具来更改API,仍然是错误的。Web浏览器不是为了测试API而设计的,甚至不是为了查看API的输出而是为了查看文档。更糟糕的是,如果有人认为某个API测试工具过于膨胀,而不是任何API开发人员必须使用的工具包的一部分,说实话,我也会添加前端开发人员,因为他们也需要与API进行交互和试验。这可能还不够,因为没有插件的浏览器不允许设置标头,发布到API甚至检查响应标头。
user3285954

我了解您在说什么,而且您没看错。但是,只是题外话,您不赞成投票的原因是您回答问题的语气。您听起来非常好斗,并且以那种认为他们知道一切的开发人员的身份碰到了,这真是令人反感。从您的回应来看,我确定您是一位出色的开发人员。但是,您必须学习,尤其是在这样的专业质量检查环境中,才能以更友好,更人性化的方式与他人交谈和说服。也许,首先给出他们想要的答案,然后解释一个更好的方法,并激发出为什么会更好。
tno2007
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.