Supporting only JSON in ASP.NET Web API – the right way

Sometimes (or perhaps, quite often?) you only need to support JSON in your ASP.NET Web API. In these cases, the ability of Web API pipeline to facilitate various media types is of no value for you – and you probably do not care at all about content negotiation.

In such situations it is often suggested to remove other media type formatters and only leave JsonMediaTypeFormatter. In fact, the author of this blog has earned almost 20 StackOverflow points for this type of suggestion.

However, there is even better way to solve this problem, and you’ll love it if you are into micro-optimizations.

JSON in Web API – the formatter based approach

As mentioned in the introduction, the most common approach to support JSON only is to clear other formatters and leave only JsonMediaTypeFormatter around.

Given an instance of HttpConfiguration you’d simply clear all and re-add JsonMediaTypeFormatter:

However, the caveat here is that even though we cleared all other formatters; the entire content negotiation process is still happening – which is a tiny overhead, you shouldn’t really have to pay for. Because we do know the outcome already, so why waste any cycles at all with conneg?

Enter approach number 2 – customizing content negotiation – which happens to be better suited for this task.

JSON in Web API – the conneg based approach

The better way to achieve this goal is to replace the default Web API’s content negotiation mechanism (or, in short, conneg), with a custom one that doesn’t do anything except yields JSON result straight away.

The extensibility interface for conneg is IContentNegotiator, and it’s Negotiate method. It’s role is to take the Type definition, request and the collection of formatters – all these products will participate in the conneg process.

Based on those “ingredients”, it then returns a ContentNegotiationResult which is a wrapper object around the outcome of the negotiation – the selected headers and the selected formatter.

Following the feedback from Youssef Moussaoui from ASP.NET team, I have changed the original approach a bit. In this specific scenario, we will pass in an instance of JsonMediaTypeFormatter into a customized conneg negotiator to always return the content type of application/json and the predefined formatter – JsonMediaTypeFormatter. This way we avoid re-creating the formatter per every request, and also we allow the user to pass in custom serializer settings.

Now all that’s left to do is to register the new mechanism against your instance of the HttpConfiguration:

So now, instead of relying on DefaultContentNegotiator, which does a lot of things in its Negotiate implementation, we plugged in a custom one that only supports JSON and immediately returns that.

On a side note, you may wish to revisit my post about Content Negotiation to understand better what each of these steps does and how to customize it. Bottom line here is, that with this custom IContentNegotiator you have, in an elegant and performance friendly way got rid of all content negotiation in your application and directed everything towards being JSON based only.

Naturally, if you now run your application, every single request will use only your new IContentNegotiator.

  • Pingback: Supporting only JSON in ASP.NET Web API - the r...()

  • Tugberk Ugurlu

    Very nice post, thanks!

    what about conneg and Accept-Charset header in this case? refer to: Did have a chance to look it up through the source code but maybe you did.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1369()

  • Pingback: Dew Drop – June 4, 2013 (#1,560) | Alvin Ashcraft's Morning Dew()

  • Steve Gourley

    In this approach it seems that serialization settings aren’t honored. Is that expected?

    • Filip W

      yeah expected – that was intended to be a simple example. With that said, there are considerations for not recreating the formatter per request, so I updated the code and now you can provide your own serializer settings

  • Jalpesh Vadgama

    Nice post!!

  • Agustin Colchado

    Very useful post! I was looking into this since I really only need to support JSON and wanted to reduce the overhead.

    Any known side affects? Negative or positive ones?

  • Raju Golla

    protected void Application_Start()



    As Web API returns by default returns xml or Json data, clearning xmlFormatters outputs Json data. of course this is ‘other way around’.

    • Ashok Solanki

      thnaks man …. really great help for me

  • Dmitry Pavlov

    Thanks! This way is the most elegant I saw.

  • Md.Ibrahim

    That is genius!

    • Luís Gabriel Nascimento Simas


  • trondhuso

    Now, if you want to support both json and xml? I understand I have to add XmlMediaTypeFormatter and JsonMediaTypeFormatter. How do I then check for which on in the constructor?
    And what about the Negotiate?

    • Filip W

      then you don’t do anything, since json and xml are supported out of the box

      • trondhuso

        yes, right. Let me rephrase the question. What if I want to have more control on how the XML and/or the Json is generated. Do I still use the out of the box formatters, or do I create my own formatters?

        Btw: Very nice posts on formatters and also conneg.

  • Domaa

    Where/how exactly do you get the config object from and what namespaces do you need to import? I’m trying to do this in the CS file for my WEbService

  • J Dunlavy

    Thank you very much!

  • Malcolm Learner

    I really liked this at first, but then ran into problems. It seems that the negotiator was return null values for HTTP methods I had not specified anything for. This, in turn, caused the Swagger-UI library I am using to fail. What other problems might come up because of this?

    “host”: “localhost:54808″,
    “basePath”: null,
    “schemes”: [“http”],
    “consumes”: null,
    “produces”: null,
    “paths”: {
    “/MyResource”: {
    “$ref”: null,
    “get”: null, <——– problem here
    "put": null, <——– problem here
    "post": {
    "tags": ["MyResource"],
    "summary": null,
    "description": null,
    "externalDocs": null,
    "operationId": "MyResource_Post",

  • Hal Diggs

    still works, nice