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.