joydip_kanjilal
Contributor

How to work with content negotiation in Web API

opinion
Jun 15, 20164 mins
Software Development

Content negotiation in Web API helps determine the best representation of a resource from among the various representations available

ASP.Net Web API is a lightweight framework used for building stateless and RESTful HTTP services. RESTful services are lightweight, stateless, client-server based, cacheable services that are based on the concept of resources. REST is an architectural style — a set of constraints used to implement stateless services. It is an architectural paradigm that is used to create reusable, scalable services.

Representation of a resource in the format requested for is an interesting topic since you might often want to consume your services from various types of devices. Content negotiation is one of the most important concepts in Web API. Although a relatively simple concept, there are many misconceptions and misunderstandings around this topic. When designing and implementing RESTful services using Web API, you would often need to deal with content negotiation.

What is negotiated content and why is it important?

Content negotiation may be defined as the process of inspecting the structure of an incoming HTTP request to determine the best representation of a resource from amongst multiple available representations of the same resource. In essence, content negotiation is a concept that allows the same Url to serve the same content in various formats. You can take advantage of content negotiation to select the preferred media type.

In Web API, content negotiation is performed by the runtime (at the server side) to determine the media type formatter to be used based to return the response for an incoming request from the client side.

Content negotiation is centered on Media type and Media type formatter. While the former refers to the value of the “content-type” header in HTTP request and HTTP response, the latter is used to convert .NET types to corresponding HTTP data and vice-versa. Note that media type formatter in Web API is represented by an abstract class called MediaTypeFormatter.

The Web API framework comes with the following formatters by default.

  • System.Net.Http.Formatting.JsonMediaTypeFormatter
  • System.Net.Http.Formatting.XmlMediaTypeFormatter
  • System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter
  • System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter

To customize content negotiation in Web API, the main extensibility point that you would need to take advantage of, is media type mapping. Note that Web API comes up with the following media type mappings by default.

  • QueryStringMapping
  • UriPathExtensionMapping
  • RequestHeaderMapping
  • MediaRangeMapping

To build you custom media type mapping, you would need to create a class that extends the MediaTypeMapping as shown in the code snippet below.

public class IDGMediaTypeMapping : MediaTypeMapping

{

   protected override double OnTryMatchMediaType(HttpResponseMessage response)

     {

                //Write your custom code here

     }

}

The following code snippet illustrates how you can retrieve the names of all supported formatters in Web API by iterating the HttpConfiguration.Formatters collection.

   [HttpGet]

       public List<string> GetAllFormatters()

       {

           List<string> lstFormaters = new List<string>();

           foreach (var formatter in this.Configuration.Formatters)

           {

               lstFormaters.Add(formatter.GetType().Name);

           }

           return lstFormaters;

       }

Let’s now explore how we can work with content negotiation to select the formatter we want and retrieve the content in the format we need. Consider the following entity class.

public class CustomerDTO

   {

       public Int32 Id

       { get; set; }

       public string FirstName

       { get; set; }

       public string LastName

       { get; set; }

       public string Address

      { get; set; }

   }

Next, assume that you have a method that populates data into a list of type CustomerDTO and returns it.

private List<CustomerDTO> GetCustomerData()

       {

           List<CustomerDTO> lstCustomers = new List<CustomerDTO>();

           CustomerDTO customer = new CustomerDTO();

           customer.Id = 1;

           customer.FirstName = "Joydip";

           customer.LastName = "Kanjilal";

           customer.Address = "Hyderabad, India";

           lstCustomers.Add(customer);

           return lstCustomers;

       }

The following Web API method shows how you can return HttpResponseMessage as a response from your Web API method based on the default content negotiation mechanism available.

[HttpGet]

       public HttpResponseMessage GetCustomers()

       {

           List<CustomerDTO> lstCustomers = GetCustomerData();

           IContentNegotiator negotiator = Configuration.Services.GetContentNegotiator();

           ContentNegotiationResult result = negotiator.Negotiate(typeof(CustomerDTO), Request, Configuration.Formatters);

           return new HttpResponseMessage()

           {

               Content = new ObjectContent<IEnumerable<CustomerDTO>>(lstCustomers, result.Formatter, result.MediaType.MediaType)

         };

       }

If you were to use a specific formatter available in the formatters collection, you may want to re-write the same method as shown in the code snippet below.

[HttpGet]

       public HttpResponseMessage GetCustomers()

       {

           List<CustomerDTO> lstCustomers = GetCustomerData();

           return new HttpResponseMessage()

           {

               Content = new ObjectContent<IEnumerable<CustomerDTO>>(lstCustomers, Configuration.Formatters[1])

           };

      }

Ok; but how do you build your own custom formatter then? Well, to create a custom media type formatter, you should create a class that extends the MediaTypeFormatter abstract class. You should then write your custom code inside the class you created to override the methods of the MediaTypeFormatter abstract base class.

public class IDGCustomMediaTypeFormatter : MediaTypeFormatter

   {

       public override bool CanReadType(Type type)

       {

           throw new NotImplementedException();

       }

       public override bool CanWriteType(Type type)

       {

           throw new NotImplementedException();

       }

   }

Once your custom formatter is in place, you can add it to the formatters collection easily: config.Formatters.Add(new IDGCustomMediaTypeFormatter ());

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author