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


当前回答

I like Felipe Leusin's approach best - make sure browsers get JSON without compromising content negotiation from clients that actually want XML. The only missing piece for me was that the response headers still contained content-type: text/html. Why was that a problem? Because I use the JSON Formatter Chrome extension, which inspects content-type, and I don't get the pretty formatting I'm used to. I fixed that with a simple custom formatter that accepts text/html requests and returns application/json responses:

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

其他回答

如果你在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项目类型,因此没有这个类开始,请参阅这个答案关于如何合并它的详细信息。

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

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

这个问题的问题在客户端,而不是API。web API根据浏览器的请求正确地工作。

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

它应该是当前的,我试过了,它工作。

你只需要像这样修改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}"
       );
    }

从这个问题被问到(和回答)已经过去了一段时间,但是另一个选择是在请求处理过程中使用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;
    }
}