ASP.NET Web API MediaTypeFormatters With MediaTypeMappings
We will see how Content-Negotiation (Conneg) Algorithm works on ASP.NET Web API with MediaTypeFormatters and MediaTypeMappings
3/3/2012 11:38:00 AM
1 comment
7792 times
If you have read my post on Getting Started With ASP.NET Web API, you probably saw me talking about exposing your data to the world with various types of formats. This feature has been made possible by formatters. Formatters handles serializing and deserializing strongly-typed objects. For two days, I have been really looking into formatters and explored a lot of useful stuff and I thought that sharing those would be great.
ASP.NET Web API beta was shiped with 3 different formatters: JsonMediaTypeFormatter, XmlMediaTypeFormatter, FormUrlEncodedMediaTypeFormatter. All these classes are derived from MediaTypeFormatter abstract class. As you might guess, it is fairly easy to create one and hook it up but in this post, I won’t talk about custom MediaTypeFormatters. I would like to talk about how they are being chosen and assigned to process the request by the framework, especially on MediaTypeMappings. ASP.NET Web API decides which formatter to process request with according to its Content-Negotiation (Conneg) Algorithm. Kiran Challa has two great blog posts on this:
On these posts, you will find how the Conneg algorithm works inside the framework. It has various options and as default it looks at the http headers to decide the most suitable format. For this post, I have created a very simple Web API project. I did that by creating an empty ASP.NET Web Application, installing AspNetWebApi nuget package (had to install System.Json package separately). Then I registered my route: protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute( "defaultHttpRoute", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } Finally, I created a simple API: public class CarsController : ApiController { public string[] Get() { return new string[] { "BMW", "Ferrari", "FIAT" }; } } When I fire up the development web server IIS Express and navigate to /api/cars, I get the list of cars as expected. This is not the clearest way of explaining it, is it? Let’s see the headers: Request: GET http://localhost:4446/api/cars HTTP/1.1 Response: HTTP/1.1 200 OK 18 As you see, we have the response back as json because it is the first formatter registered (yes, order matters) by default and we didn’t specify which format we are interested in. When you add "Accept: application/xml" to your request, you will see that you will be getting the response back as xml. Approve it or not, this is the RESTFul way of negotiating between client and server. But sometimes we would like to decide the format according to QueryString. If so, you have an OOB support for this. Intro to MediaTypeMappings By default, Accept and Request Content-Type headers play role on deciding which format you serve. One other way of involving a formatter to process your request is MediaTypeMapping. MediaTypeMapping provides a way for us to participate the Conneg algorithm decision making process and decide if we would like the formatter to take part in writing the response. There are several built in MediaTypeMappings (actually 4) supported out of the box. These are QueryStringMapping, RequestHeaderMapping, UriPathExtensionMapping, MediaRangeMapping. All these classes are derived from MediaTypeMapping abstract class (yes, creating a custom one is tedious and I plan on writing a post on that as well). We have these mappings and the other great stuff is that all default formatters has a hook up point in order to register mappings. Let’s assume that we would like to decide the format of response based on a query string value as well. As we have QuesryStringMapping, we can use this and can provide our data on json format if request comes with ?format=json quesry string and xml format if it is ?format=xml. Here is the configuration in order to enable this: protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute( "defaultHttpRoute", routeTemplate: "api/{controller}" ); GlobalConfiguration.Configuration.Formatters.JsonFormatter. MediaTypeMappings.Add( new QueryStringMapping( "format", "json", "application/json" ) ); GlobalConfiguration.Configuration.Formatters.XmlFormatter. MediaTypeMappings.Add( new QueryStringMapping( "format", "xml", "application/xml" ) ); } When we make a request with accept header and format query string, we will see that framework honors our mapping registrations: Request: GET http://localhost:4446/api/cars?format=xml HTTP/1.1 Response: HTTP/1.1 200 OK e9 Pretty powerful stuff. Enjoy Additional allowed tags : [quote]...[/quote], [user]...[/user]
|
Keep in Touch with MeTagsArchive
Blogroll |





how do I use xml string in post method?. I can't map it to a class since the format is unknown. webapi fails with mediaformat error. I tried using StringContent in my post method and removed the jsonformatter but doen't help.