1220
votes

Using the newer ASP.NET Web API, in Chrome I am seeing XML - how can I change it to request JSON so I can view it in the browser? I do believe it is just part of the request headers, am I correct in that?

29
There is a discussion here to make returning JSON only the default behavior: github.com/aspnet/Mvc/issues/1765Natan

29 Answers

1797
votes

I just add the following in App_Start / WebApiConfig.cs class in my MVC Web API project.

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

That makes sure you get JSON on most queries, but you can get XML when you send text/xml.

If you need to have the response Content-Type as application/json please check Todd's answer below.

NameSpace is using System.Net.Http.Headers.

509
votes

If you do this in the WebApiConfig you will get JSON by default, but it will still allow you to return XML if you pass text/xml as the request Accept header

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

If you are not using the MVC project type and therefore did not have this class to begin with, see this answer for details on how to incorporate it.

333
votes

Using RequestHeaderMapping works even better, because it also sets the Content-Type = application/json in the response header, which allows Firefox (with JSONView add-on) to format the response as JSON.

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

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

Register like so:

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

MVC4 Quick Tip #3–Removing the XML Formatter from ASP.Net Web API

In Global.asax add the line:

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

like so:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

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

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

In the WebApiConfig.cs, add to the end of the Register function:

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

Source.

97
votes

In the Global.asax I am using the code below. My URI to get JSON is 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"));
}
54
votes

Have a look at content negotiation in the WebAPI. These (Part 1 & Part 2) wonderfully detailed and thorough blog posts explain how it works.

In short, you are right, and just need to set the Accept or Content-Type request headers. Given your Action isn't coded to return a specific format, you can set Accept: application/json.

45
votes

As the question is Chrome-specific, you can get the Postman extension which allows you to set the request content type.

Postman

35
votes

One quick option is to use the MediaTypeMapping specialization. Here is an example of using QueryStringMapping in the Application_Start event:

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

Now whenever the url contains the querystring ?a=b in this case, Json response will be shown in the browser.

33
votes

This code makes json my default and allows me to use the XML format as well. I'll just append the xml=true.

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

Thanks everyone!

23
votes

Don't use your browser to test your API.

Instead, try to use an HTTP client that allows you to specify your request, such as CURL, or even Fiddler.

The problem with this issue is in the client, not in the API. The web API behaves correctly, according to the browser's request.

18
votes

Most of the above answers makes perfect sense. Since you are seeing data being formatted in XML format ,that means XML formatter is applied,SO you can see JSON format just by removing the XMLFormatter from the HttpConfiguration parameter like

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

since JSON is the default format

12
votes

I used a global action filter to remove Accept: application/xml when the User-Agent header contains "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();
    }
}

Seems to work.

11
votes

I found the Chrome app "Advanced REST Client" excellent to work with REST services. You can set the Content-Type to application/json among other things: Advanced REST client

11
votes

Returning the correct format is done by the media-type formatter. As others mentioned, you can do this in the WebApiConfig class:

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

        ...
    }
}

For more, check:

In case your actions are returning XML (which is the case by default) and you need just a specific method to return JSON, you can then use an ActionFilterAttribute and apply it to that specific action.

Filter attribute:

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

Applying to action:

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

Note that you can omit the word Attribute on the action decoration and use just [JsonOutput] instead of [JsonOutputAttribute].

8
votes

as per latest version of ASP.net WebApi 2,

under WebApiConfig.cs , this will work

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

It's unclear to me why there is all of this complexity in the answer. Sure there are lots of ways you can do this, with QueryStrings, headers and options... but what I believe to be the best practice is simple. You request a plain URL (ex: http://yourstartup.com/api/cars) and in return you get JSON. You get JSON with the proper response header:

Content-Type: application/json

In looking for an answer to this very same question, I found this thread, and had to keep going because this accepted answer doesn't work exactly. I did find an answer which I feel is just too simple not to be the best one:

Set the default WebAPI formatter

I'll add my tip here as well.

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

I do have a question of where the defaults (at least the ones I am seeing) come from. Are they .NET defaults, or perhaps created somewhere else (by someone else on my project). Anways, hope this helps.

6
votes

You can use as below:

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

Here is a solution similar to jayson.centeno's and other answers, but using the built-in extension from 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
 }

The solution was primarily geared toward supporting $format for OData in the early releases of WebApi, but it also applies to the non-OData implementation, and returns the Content-Type: application/json; charset=utf-8 header in the response.

It allows you to tack &$format=json or &$format=xml to the end of your uri when testing with a browser. It does not interfere with other expected behavior when using a non-browser client where you can set your own headers.

5
votes

Just add those two line of code on your WebApiConfig class

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


          ............................
      }
}
3
votes

You just change the App_Start/WebApiConfig.cs like this:

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

From MSDN Building a Single Page Application with ASP.NET and AngularJS (about 41 mins in).

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

It should be current, I tried it and it worked.

2
votes

Some time has passed since this question was asked (and answered) but another option is to override the Accept header on the server during request processing using a MessageHandler as below:

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

Where someOtherCondition can be anything including browser type, etc. This would be for conditional cases where only sometimes do we want to override the default content negotiation. Otherwise as per other answers, you would simply remove an unnecessary formatter from the configuration.

You'll need to register it of course. You can either do this globally:

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

or on a route by route basis:

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

And since this is a message handler it will run on both the request and response ends of the pipeline much like an HttpModule. So you could easily acknowledge the override with a custom header:

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
votes

Here is the easiest way that I have used in my applications. Add given below 3 lines of code in App_Start\\WebApiConfig.cs in Register function

    var formatters = GlobalConfiguration.Configuration.Formatters;

    formatters.Remove(formatters.XmlFormatter);

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

Asp.net web API will automatically serialize your returning object to JSON and as the application/json is added in the header so the browser or the receiver will understand that you are returning JSON result.

1
votes

Using Felipe Leusin's answer for years, after a recent update of core libraries and of Json.Net, I ran into a System.MissingMethodException:SupportedMediaTypes. The solution in my case, hopefully helpful to others experiencing the same unexpected exception, is to install System.Net.Http. NuGet apparently removes it in some circumstances. After a manual installation, the issue was resolved.

1
votes

WebApiConfig is the place where you can configure whether you want to output in json or xml. By default, it is xml. In the register function, we can use HttpConfiguration Formatters to format the output.

System.Net.Http.Headers => MediaTypeHeaderValue("text/html") is required to get the output in the json format.

enter image description here

-3
votes

I'm astonished to see so many replies requiring coding to change a single use case (GET) in one API instead of using a proper tool what has to be installed once and can be used for any API (own or 3rd party) and all use cases.

So the good answer is:

  1. If you only want to request json or other content type install Requestly or a similar tool and modify the Accept header.
  2. If you want to use POST too and have nicely formatted json, xml, etc. use a proper API testing extension like Postman or ARC.