Formatters in ASP.NET MVC 6

One of the key concepts in HTTP API development is the notion of content negotiation (conneg). ASP.NET Web API provided first class support for content negotiation through the use of MediaTypeFormatters.

While MVC 6 is a de facto brand new framework, rebuilt from scratch, the majority of concepts from MVC 5 and Web API 2 have naturally been brought forward, and conneg done through formatters are one of them.

Let’s have a look at formatters in MVC6.

Input and Output formatters

While in ASP.NET Web API formatters were bi-directional – single object handling both input and output, in MVC 6 the concept of formatters became uni-directional.

This is represented by two interfaces – IOutputFormatter and IInputFormatter.

Additionally, just like in Web API there is a base class to make extensibility a little more convenient – it’s available for output formatters only though.

All in all, building custom formatters is almost identical as it was in Web API – you have to deal with read/write operations (depending on the direction of the formatter), declare the supported content types and define what Types are supported.

What’s in the box?

MVC 6 ships with a bunch of formatters defined already.

Three input formatters:

  • JsonInputFormatter – based on JSON.NET
  • XmlSerializerInputFormatter – based on XmlSerializer (in the box, but not registered by default)
  • XmlDataContractSerializerInputFormatter – based on DataContractSerializer

Six output formatters:

  • JsonOutputFormatter – based on JSON.NET
  • XmlSerializerOutputFormatter – based on XmlSerializer (in the box, but not registered by default)
  • XmlDataContractSerializerOutputFormatter – based on DataContractSerializer
  • TextPlainFormatter – used to force a string into a text/plain content type
  • HttpNoContentOutputFormatter – used to force 204 status code for null action return
  • HttpNotAcceptableOutputFormatter – used to force 406 status code if no appropriate formatter can be selected to handle the request (in the box, but not registered by default)

This is a slight change from Web API which itself defined four formatters – JSON, XML and two formatter specialized in handling form data.

Customizing formatters

In order to add/remove formatters you have tweak the new MvcOptions object which allows you to control the global configuration of the MVC framework. MvcOptions exposes input/output formatters collections.

You get to deal with MvcOptions inside the ConfigureServices method of your Startup class, as you are adding MVC to the service collection. An example below shows getting rid of the XML formatter – we get rid of them twice since obviously we deal with input and output formatters separately.

Similarly, you can customize existing formatters i.e. JSON formatter, and define the relevant serializer settings that would match your application’s requirements. For example:

HttpNoContentOutputFormatter, TextPlainFormatter and HttpNotAcceptableOutputFormatter

Let’s have a closer look at the three new types of output formatters – in order to understand the reason why they have been added in this iteration of MVC.

HttpNoContentOutputFormatter converts null responses from your actions into a 204 No Content status code. This is a change from Web API, where a null return would end up being serialized into JSON or XML. Additionally, if you return void or Task from an action, this formatter would also kick in. Functionally, this is the same behavior as in Web API, however there it was not achieved via a formatter, but through a ResultConverter.

You can disable the null value handling on the HttpNoContentOutputFormatter by setting its TreatNullValueAsNoContent property to false.

TextPlainFormatter converts a string return type into an HTTP response with a body using text/plain content type. Similarly to HttpNoContentOutputFormatter this is a change in comparison to Web API, where a string would get treated just like any other type and get serialized into JSON or XML.

Finally, HttpNotAcceptableOutputFormatter is a formatter that allows you to disable the matching on Type when it comes to content negotiation. If a relevant formatter cannot be selected, MVC6 (similarily to Web API) would just default to JSON, because it would select a formatter strictly on the fact that it can serialize the Type being return. This is quite problematic, because you might have a client requesting i.e. text/csv and the framework happily returns response 200 with JSON.

In Web API you’d disable matching on Type by customizing DefaultContentNegotiator. In MVC6 it’s slightly simpler as you simply need to add the HttpNotAcceptableOutputFormatter to the output formatters collection.

  • Dave Van den Eynde

    Great to see this, I’ve been waiting for this. Just a question: is text/html also handled by this content negotiation to render views?

    • Filip W

      no, not out of the box – you need to return ViewResult explicitly. Could be added though, similarly to how we have done in WebApiContrib

  • abatishchev

    Will not RemoveAll(formatter => formatter.Instance is JsonOutputFormatter) work better here?

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

  • andersaberg

    @Filip We are building a new web platform at my company. When do you think vNext (MVC 6) is stable enough to run in production? Our aim for production is in the beginning of summer.

    • Filip W

      the announced release was Q2 2015 so you should be good to go then

      • andersaberg

        Thanks Filip!

      • jamescrosswell

        Maybe that should be 2016 rather than 2015 😉

  • Pingback: Katpro Technologies Pvt Ltd | Formatters in ASP.NET MVC 6!!!!!!!!!!!()

  • William Smith

    Will ODATA controllers be supported? I have not seen this with the vNext stuff. I have both customer serializers and deserializers for ODATA based on the current webAPI stack.

  • nonintanon

    Awesome. Thanks!!

  • anavgale

    Hi @Filip , I am trying to register DataContractResolver to use PATCH verb in MVC6, but not able to do that. Any pointer you can give?

  • Pingback: Links of the month (November Edition) | Jan @ Development()

  • Pingback: Getting started with ASP.NET 5/ vNext and MVC 6 | Bits nor Bytes()

  • Alex

    How can i use Bson within MVC 6. I dont know what to do? Must i built a new formattertyp or can i customize serialzersettings ? Can anyone help me ?


  • Muhammad Rehan Saeed

    What about the BSON formatter. Does this still exist or is it in the pipeline?

  • Pingback: Angular $ to a ASP MVC 6 Web Api - DexPage()

  • Fred Peters

    Apparently the Configure option was removed from services.AddMvc() in either beta 6 or 7, so this solution does not work for the latest version. I’m still trying to get something to work and am about to go back to the class attributes of the bad old days.

    Thanks for all your posts Filip, it’s amazing how many searches I do for problems bring me to your site.

  • Fred Peters

    The camel casing option is now:

    services.AddMvc().AddJsonOptions(options =>
    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();