Removing the XML Formatter from ASP.NET Web API Applications
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:
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.
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:
It's a simple solution to a small debugging task that's made my life easier. Maybe you find it useful too…
The Voices of Reason
# re: Removing the XML Formatter from ASP.NET Web API Applications
http://codebetter.com/glennblock/2012/02/26/disabling-the-xml-formatter-in-asp-net-web-apithe-easy-way-2/
# re: Removing the XML Formatter from ASP.NET Web API Applications
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
# re: Removing the XML Formatter from ASP.NET Web API Applications
Great approach, simplifies things. A small tip, in RegisterApis method you could use Any(blah) instead of Where(blah).Count > 0
Also maybe it makes sense to have this functionality available only in DEBUG, I'd personally put #if DEBUG / #endif around it.
Cheers
Vlad
# re: Removing the XML Formatter from ASP.NET Web API Applications
If you are using firefox, you can use this add-in to rewrite headers using custom rules https://code.google.com/p/headertool/ and leave your API intact - not to mention that there are some nice add-ins for viewing the JSON too https://addons.mozilla.org/en-US/firefox/addon/jsonview/
# re: Removing the XML Formatter from ASP.NET Web API Applications
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
Which accomplishes the same end result in a slightly different way in one easy to read line of code.
# re: Removing the XML Formatter from ASP.NET Web API Applications
# re: Removing the XML Formatter from ASP.NET Web API Applications
GlobalConfiguration.Configuration.Formatters[0].SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
# re: Removing the XML Formatter from ASP.NET Web API Applications
@Gene - Excellent tip to add text/xml to the media type headers!
# re: Removing the XML Formatter from ASP.NET Web API Applications
// This method allows the client to override their browser's HTTP Accept header by putting a value in the querystring. GlobalConfiguration.Configuration.Filters.Add(new FormattingOverrideFilterAttribute(formatPreferenceOverride: "application/json", clearOtherPreferredMediaTypes: true)); ... public class FormattingOverrideFilterAttribute : ActionFilterAttribute{ /// <summary> /// Allows overriding the Accept header by querystring or server preference. /// </summary> /// <param name="formatPreferenceOverride">If defined, this mime type will be injected into the Accept header of every request.</param> /// <param name="newQuality">Optional, The quality setting for this media type. Should be between 1 and 0.</param> /// <param name="clearOtherPreferredMediaTypes">If true, will remove all other media types from the Accept header.</param> public FormattingOverrideFilterAttribute(string formatPreferenceOverride = null, double? newQuality = null, bool clearOtherPreferredMediaTypes = false) : base() { NewQualityValue = newQuality; FormatPreferenceOverride = formatPreferenceOverride; ClearOtherPreferredMediaTypes = clearOtherPreferredMediaTypes; } public double? NewQualityValue { get; set; } public string FormatPreferenceOverride { get; set; } public bool ClearOtherPreferredMediaTypes { get; set; } public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { var qs = actionContext.Request.RequestUri.ParseQueryString(); var requestedMediaType = (qs["f"] ?? qs["format"] ?? FormatPreferenceOverride ?? String.Empty).ToLower(); switch (requestedMediaType) { case "xml": case "x": requestedMediaType = "application/xml"; break; case "j": case "js": case "json": requestedMediaType = "application/json"; break; } if (String.IsNullOrEmpty(requestedMediaType)) return; // No action is necessary because no override was requested. var acceptHeaders = actionContext.Request.Headers.Accept; MediaTypeWithQualityHeaderValue header = null; if (ClearOtherPreferredMediaTypes) { var newAcceptHeaders = acceptHeaders.Where(h => h.MediaType == requestedMediaType || h.MediaType == "*/*").ToList(); acceptHeaders.Clear(); newAcceptHeaders.ForEach(acceptHeaders.Add); } header = acceptHeaders.FirstOrDefault(h => h.MediaType == requestedMediaType); if (header == null) { header = new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(requestedMediaType); acceptHeaders.Add(header); } System.Diagnostics.Debug.WriteLine("Overidding HttpAccept header for format preference."); header.Quality = NewQualityValue; } }
# re: Removing the XML Formatter from ASP.NET Web API Applications
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
======> config.Formatters.Remove(config.Formatters.XmlFormatter);
The Above one liner does the job. // this defaults to JSON formatting.
}
# re: Removing the XML Formatter from ASP.NET Web API Applications