ASP.NET Web API's default output format is supposed to be JSON, but when I access my Web APIs using the browser address bar I'm always seeing an XML result instead. When working on AJAX application I like to test many of my AJAX APIs with the browser while working on them. While I can't debug all requests this way, GET requests are easy to test in the browser especially if you have JSON viewing options set up in your various browsers.

If I preview a Web API request in most browsers I get an XML response like this:

XmlView

Why is that?

Web API checks the HTTP Accept headers of a request to determine what type of output it should return by looking for content typed that it has formatters registered for. This automatic negotiation is one of the great features of Web API because it makes it easy and transparent to request different kinds of output from the server.

In the case of browsers it turns out that most send Accept headers that look like this (Chrome in this case):

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Web API inspects the entire list of headers from left to right (plus the quality/priority flag q=) and tries to find a media type that matches its list of supported media types in the list of formatters registered. In this case it matches application/xml to the Xml formatter and so that's what gets returned and displayed.

To verify that Web API indeed defaults to JSON output by default you can open the request in Fiddler and pop it into the Request Composer, remove the application/xml header and see that the output returned comes back in JSON instead.

Fiddler

An accept header like this:

Accept: text/html,application/xhtml+xml,*/*;q=0.9

or leaving the Accept header out altogether should give you a JSON response. Interestingly enough Internet Explorer 9 also displays JSON because it doesn't include an application/xml Accept header:

Accept: text/html, application/xhtml+xml, */*

which for once actually seems more sensible.

Removing the XML Formatter

We can't easily change the browser Accept headers (actually you can by delving into the config but it's a bit of a hassle), so can we change the behavior on the server? When working on AJAX applications I tend to not be interested in XML results and I always want to see JSON results at least during development. Web API uses a collection of formatters and you can go through this list and remove the ones you don't want to use - in this case the XmlMediaTypeFormatter.

To do this you can work with the HttpConfiguration object and the static GlobalConfiguration object used to configure it:

    protected void Application_Start(object sender, EventArgs e)
    {

        // Action based routing (used for RPC calls)
        RouteTable.Routes.MapHttpRoute(
            name: "StockApi",
            routeTemplate: "stocks/{action}/{symbol}",
            defaults: new
            {
                symbol = RouteParameter.Optional,
                controller = "StockApi"
            }
        );

        // WebApi Configuration to hook up formatters and message handlers
        RegisterApis(GlobalConfiguration.Configuration);
    }

    public static void RegisterApis(HttpConfiguration config)
    {
        // remove default Xml handler
        var matches = config.Formatters
                            .Where(f => f.SupportedMediaTypes
                                         .Where(m => m.MediaType.ToString() == "application/xml" ||
                                                     m.MediaType.ToString() == "text/xml")
                                         .Count() > 0)
                            .ToList() ;
        foreach (var match in matches)
            config.Formatters.Remove(match);    
    }
}

That LINQ code is quite a mouthful of nested collections, but it does the trick to remove the formatter based on the content type. You can also look for the specific formatter (XmlMediatTypeFormatter) by its type name which is simpler, but it's better to search for the supported types as this will work even if there are other custom formatters added.

Once removed, now the browser request results in a JSON response:

JsonResponse

It's a simple solution to a small debugging task that's made my life easier. Maybe you find it useful too…