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 Answers
Note: Read the comments of this answer, it can produce a XSS Vulnerability if you are using the default error handing of WebAPI
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
.
-
120This is a surprisingly overlooked answer, and although the original question wasn't totally clear, this directly makes JSON the default response for a web browser (which sends Accept: text/html). Good job.– gregmacCommented Jan 15, 2013 at 1:44
-
17+1 Far and away the best answer. I imagine there are a ton of ppl who opt to completely remove XML just because they don't see JSON in the browser. Commented Nov 16, 2013 at 9:51
-
4I found when I did this that data provided by a third party with HTML break tags in it ended up with carriage returns. The JSON was then invalid. Better to use the accepted answer if this affects you.– StonetipCommented Mar 14, 2014 at 15:03
-
25Note that the response's
Content-Type
header will still betext/html
.– MrchiefCommented May 2, 2014 at 17:29 -
86This is horrible. The response content type header should be application/json. This "solution" makes it text/html. Commented Jul 10, 2014 at 21:01
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.
Note: This removes the support for 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);
}
}
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.
-
52Just to note, the original behaviour is correct. Chrome requests
application/xml
with a priority of 0.9 and*/*
with a priority of 0.8. By removingapplication/xml
you remove the ability for the Web API to return XML if the client requests that specifically. e.g. if you send "Accept: application/xml" you will still receive JSON.– porgesCommented Mar 26, 2013 at 21:20 -
12Is it me, or is the first sentence incorrect? The code appears to totally remove XML, not simply change the default.– NickGCommented Apr 9, 2013 at 18:24
-
6@NickG: a solution that is overlooked here and IMHO is a much better option (keeping application/xml) is the solution proposed by Felipe Leusin lower on this page. Using config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));– CohenCommented Jul 3, 2013 at 10:10
-
1So, how do we do it via web config so we get json by default and XML if requested?– KyleCommented Sep 3, 2013 at 1:40
-
4@Felipse Leusin's answer below is actually shorter and works better. Commented Sep 9, 2013 at 13:20
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"));
This option is also good for old aspx websites, add the above to Global.asax Application_Start
method.
-
8This is the most lean and simplest solution and Fiddler also detects the content type being returned as josn. Commented Mar 7, 2015 at 21:06
-
12
-
9Worked for me. I needed to add a using System.Net.Http.Formatting; Commented Feb 9, 2016 at 10:03
-
1Linking for my own convenience: This answer plays nicely with another setup step I usually perform: stackoverflow.com/a/28337589/398630. Commented May 5, 2017 at 16:03
-
2And to be clear, this just changes the default. You can always get either JSON or XML simply by including the relevant "Accept" header. Commented Sep 13, 2017 at 16:24
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());
-
24In the constructor add
this.SerializerSettings.Formatting = Formatting.Indented;
if you want it pretty-printed without a browser extension. Commented May 15, 2014 at 14:48 -
11
-
9
-
9@eddiegroves you dont want pretty-print over the wire. You want the server to send the least amount of bits over the wire (ie: no spaces). Then you want the browser to format it nicely, with addons and such. Javascript needs to parse the JSON usually, why make it slower by introducing unnecessary formatting Commented Feb 12, 2015 at 20:53
-
15For the googlers who are looking for: don't forget to add
using System.Net.Http.Formatting
andusing Newtonsoft.Json
– BerrielCommented Sep 16, 2015 at 1:46
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();
}
-
9Works - much nicer having JSON be the default instead of XML. Commented Apr 15, 2012 at 22:38
-
5
-
101I tested it, and you can't. So this is removing XML support.. Ye be warned, dear google people Commented Jul 4, 2012 at 0:42
-
3If you have a look at my answer below, this will let xml still be returned if you want to but lets the site respond with JSON to the browser Commented Sep 24, 2012 at 1:17
-
3@GlennSlaven yeah your answer should be the one marked as the correct one. Commented Oct 14, 2012 at 16:46
In the WebApiConfig.cs, add to the end of the Register function:
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
-
1In MVC5, this can be done by replacing config with GlobalConfiguration.Configuration– StevenCommented Sep 19, 2013 at 13:50
-
5For a project that must support JSON only and under no circumstance can be allowed to emit XML this is by far the best option.– Luc CCommented Jul 15, 2014 at 12:45
-
1
-
3That's terrible. -- This will always return JSON no matter what, even if the client specifically asks for XML in the Content-Type header. Commented May 5, 2017 at 21:30
-
2Projects that do not test the XML version of the API as thoroughly as their JSON version should opt for this. Objects are serialized differently by the different formatters as per the link that Michael included. For example: XML formatters do not serialize read-only fields, while the JSON formatter does.– cdigginsCommented Nov 5, 2020 at 4:42
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"));
}
-
2Great one. What is your method expect a parameter? like localhost:61044/api/values/getdate?json=true,date=2012-08-01– LT.NoloCommented Sep 5, 2012 at 13:04
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
.
-
6
-
1@Spongman, yes you can. But use an extension like REST Client - most browsers have one like it. The direct typing of url in a browser is 1. Too limiting (no control over headers, cannot post data and etc); 2. Incorrect - The browser does not consume the web api as it is intended to be consumed - you cannot rely on it testing it properly. So, again, a good REST client add-on would fix that. Commented Apr 25, 2014 at 21:37
As the question is Chrome-specific, you can get the Postman extension which allows you to set the request content type.
-
In Firefox, simply go to about:config, search for accept.default and change the content of the
network.http.accept.default
configuration totext/html,application/xhtml+xml,application/json;q=0.9,application/xml;q=0.8,*/*;q=0.7
. Commented Jun 6, 2018 at 10:48 -
Or better yet, just
text/html,application/xhtml+xml;q=1.0,*/*;q=0.7
to avoid buggy hosts such as Bitbucket from accidentally serving your browser JSON in lieu of HTML. Commented Jun 6, 2018 at 11:01 -
The URL is dead. A new one is chrome.google.com/webstore/detail/postman/…. Commented Jul 2, 2018 at 4:34
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!
-
1This is the most flexible answer (and really should be the default configuration these days). To add to this answer, JSON is the default, including from browser. To view XML, add query string: ?xml=true– raider33Commented Mar 30, 2014 at 14:04
-
Tried a number of strategies. Had a simple test for both XML and JSON and this worked out of the box Commented Jun 17, 2015 at 21:55
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.
-
2This was very useful. You can also use UriPathExtensionMapping instead of QueryStringMapping if you want to use path.to/item.json– marknuzzCommented Apr 13, 2012 at 23:28
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.
-
33Why not use the browser? It is an obvious tool for it. Commented Sep 18, 2012 at 6:37
-
5I think the point here is correct and important - we should not overfix a working part of the application (the MVC WebAPI infrastructure) if the problem is caused by the client. The real use case for an Api is to be properly used (by supplying correct headers), which is responsibility of the application. I disagree with completely discarding the browser though - for testing, there are plenty of tools for almost any browser (Rest Client-like extensions to start with). Commented Apr 25, 2014 at 21:30
-
8
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
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]
.
In the 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);
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.
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
config.Formatters.Remove(config.Formatters.XmlFormatter);
-
3While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. Please read this stackoverflow.com/help/how-to-answer– S.RCommented Jul 1, 2017 at 4:52
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.
You can use as below:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
-
If you're making a WebAPI app for just passing JSON messages, consider this answer.– allen1Commented Dec 31, 2018 at 20:35
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.
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());
............................
}
}
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}"
);
}
-
Removing a formatter is generally not a good idea, you are removing functionality. Commented Feb 8, 2016 at 15:36
-
Actually in this case, it works well for me, also many others suggest a way like this. I've learned it from myview.rahulnivi.net/building-spa-angular-mvc-5 book!– vaheedsCommented Feb 8, 2016 at 19:03
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;
}
}
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 the 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.
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.
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.
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.
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:
-
Some prefer doing things without adding bloat in the form of extra tools and libraries.– tno2007Commented Feb 24, 2020 at 16:15
-
It is still wrong to make changes to the API only because someone is using the wrong tool for the job. A web browser is not designed to test APIs, not even to view the output of APIs but to view documents. It is even worse if someone thinks an API tester tool is bloat instead of part of mandatory toolkit for any API developer, and honestly I would add front end developers too because they need to interact and experiment with APIs as well. It's also probably not enough because the browser without addins doesn't allow to set headers, post to an API or even inspect response headers. Commented Feb 24, 2020 at 20:51
-
I understand what you're saying and you're not wrong. But just off-topic, the reason why you are getting down-voted is the tone in which you answer the question. You sound very combative and come across as that developer that think they know everything, and that's very distasteful. I'm certain you are a great developer, judging by your responses. But, you must learn, especially in a professional QA environment like this, to address and convince people in a friendlier and more human way. Perhaps, first give the answer they want, then explain a better way, and motivate why it's better.– tno2007Commented Feb 25, 2020 at 0:18