An important part of Web API is resource content negotiation. The HTTP protocol RFC defines content negotiation as the process of selecting the best representation for a given response when there are multiple representations available. In practise the same resource can be represented in a variety of different ways – lets say a contact information resource can be shown in JSON representation, but also in XML or even as a PNG QR code containing the same content.

The content negotiation can be either server or client driven. In the first instance, the server decides what content to send down based on the various headers sent from the client. The latter requires an additional call to the server to get the list of available representations. Web API provides you with an easy way to send different representations of the same content.

Creating new MediaTypeFormatter to Deliver QR Code

The Web API comes with MediaTypeFormatter base class. If you want to create your own formatter, simply inherit from MediaTypeFormatter. If we take the existing scenario of contact management, lets say we want to create a QR code that contains the contact information of each contact stored in the database.

Our QrMediaFormatter can only be used for writing the type of Contact. Therefore we add logic to the CanWriteType and override the WriteToStreamAsync member.

The WriteQrStream method simply takes the Contact, builds up a simple string of the contact name and email and sends the string to the Google QR chart generation API. The stream coming from the API is then directly written to the response stream.

Wire Up Your Custom Media Type Formatter

The SupportedMediaTypes property contains a collection of MediaTypeHeaderValues. These define which media types the formatter can handle. In our case we are happy just to map the QR formatter to a single type –> image/png. However, it is possible to have the same media formatter handle a variety of MediaTypeHeaderValues. For example image/png and image/jpeg.

Once we have the media type in the SupportedMediaTypes, the client can use the Content-Type request header to request the image representation of the resource. You can try it out in fiddler, accessing the contact resource with “Content-Type: image/png” header.

Map Extension to the Media Type Formatter

The idea is that the same resource should not change URI based on representation. However, it is difficult when some clients are unable to make requests for specific content type. For example, even if you use your contact resource as a path to an image /api/contact/a85ad33c-b61f-4503-8d75-861f3701efe3, the browser client does not send a content-type request for image and the service will the return a default representation of the resource, which in our case isn’t an image.

The way around it is to map a particular extension to the Media Type Formatter. It means adding an extension and therefore changing the URI, but it means it can be used by clients without specifying the requested content-type. First, you need to make sure your routes support extensions.