Content Negotiation in ASP.NET MVC4 Web API Beta – Part 1

This is my first blog post…Yay! Smile.

In this blog post, I am going to describe about the Default Content Negotiation Algorithm that gets shipped as part of ASP.NET MVC4 Beta. The Web API provides a lot of nice features with which you can build RESTful services. For more details, you can look at the release notes here.

Throughout the rest of this post, I will refer to Content-Negotiation simply as Conneg.

I use the tool called Fiddler to capture the requests and responses. I find it very useful for debugging purposes.

1. If a Request message is sent with an Accept header, Conneg algorithm will use the Accept header to decide about the Response media type and the MediaTypeFormatter to write.
This should make sense to you as here the client is asking for a response in a specific format.

Example:

Request:

GET https://kirandev:9090/DefaultConNegAlgorithmTests/GetData HTTP/1.1

Accept: application/xml Host: kirandev10:9090
Connection: Keep-Alive

Response:

HTTP/1.1 200 OK
Content-Length: 60
Content-Type: application/xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 25 Feb 2012 21:03:47 GMT

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

2. If a Request message is sent with NO Accept header and with a Content-Type header (let’s say when you are using POST to post content to the server), Conneg algorithm will use the Content-Type header to decide about the Response media type and the MediaTypeFormatter to write.

Here the Conneg algorithm uses the best-effort approach to judge which format the client could understand. Since here the client was able to post content in a particular format(let’s say ‘application/xyz’), Conneg algorithm deduces that the Client could probably understand the Response also in the same format(‘application/xyz’).

Example:

Request:

POST https://kirandev:9090/DefaultConNegAlgorithmTests/PostData HTTP/1.1

Content-Type: application/xml Host: kirandev10:9090
Content-Length: 60
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

Response:

HTTP/1.1 200 OK
Content-Length: 60
Content-Type: application/xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 25 Feb 2012 21:12:34 GMT

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

3. If a Request message is sent with an Accept header and also a Content-Type header, Conneg algorithm will use the Accept header to decide about the Response media type and the MediaTypeFormatter to write.
This should make sense to you as here the Client is asking for a Response in a specific format.

Example:

Request:

POST https://kirandev10:9090/DefaultConNegAlgorithmTests/PostData HTTP/1.1
Accept: application/xml
Content-Type: application/json
Host: kirandev10:9090
Content-Length: 7
Expect: 100-continue
Connection: Keep-Alive

"Hello"

Response:

HTTP/1.1 200 OK
Content-Length: 60
Content-Type: application/xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 25 Feb 2012 21:09:59 GMT

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

4. A variation to “Point 3.” above: If a Request message is sent with an Accept header and also a Content-Type header, then Conneg algorithm will use the Accept header to decide about the Response media type and the MediaTypeFormatter to write. 

Now, if the Conneg algorithm wasn’t able to find a formatter for the supplied media type in the Accept header, then it uses the best-effort approach and uses the Content-Type header to decide about the Response media type and the MediaTypeFormatter to write.

Example:

Request:

POST https://kirandev:9090/DefaultConNegAlgorithmTests/PostData HTTP/1.1
Accept: application/nonexisting
Content-Type: application/xml
Host: kirandev10:9090
Content-Length: 60
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

Response:

HTTP/1.1 200 OK
Content-Length: 60
Content-Type: application/xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 25 Feb 2012 21:15:50 GMT

<?xml version="1.0" encoding="utf-8"?><string>Hello</string>

5. For ALL the above scenarios from 1 to 4, if the Conneg algorithm wasn’t able to find a suitable formatter to write the Response, then by default it would send back content using the 1st formatter in the collection of MediaTypeFormatters present on the Configuration object.

Example:

Request:

GET https://kirandev10:9090/DefaultConNegAlgorithmTests/GetData HTTP/1.1
Accept: application/nonexisting
Host: kirandev10:9090
Connection: Keep-Alive

Response(Here the 1st formatter in my list is a JsonMediaTypeFormatter and hence the response is in Json format):

HTTP/1.1 200 OK
Content-Length: 7
Content-Type: application/json; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 25 Feb 2012 21:25:40 GMT

"Hello"

6. If for a particular reason, a user needs to always send a Response in a specific format and NOT caring about the Content Negotiation, we have support for it. For example, in the following piece of code, the Action called “GetOrder” is specifically setting the media type to be “application/xml”. So, Web API honors this and will not let the Conneg algorithm to overwrite it irrespective of the Request’s Accept header media type.

 public class OrdersController : ApiController
    {
        public HttpResponseMessage GetOrder()
        {
            Order order = new Order();
            order.Id = "A100";
            order.OrderedDate = DateTime.Now;
            order.OrderTotal = 150.00;

            HttpResponseMessage<Order> response = new HttpResponseMessage<Order>(order, 
                        new MediaTypeHeaderValue("application/xml"));

            return response;
        }
    }

Example:

Request:

GET https://kirandev:9090/DefaultConNegAlgorithmTests/GetOrder HTTP/1.1

Accept: application/json

Host: kirandev10:9090

Connection: Keep-Alive

Response:

HTTP/1.1 200 OK

Content-Length: 253

Content-Type: application/xml; charset=utf-8

Server: Microsoft-HTTPAPI/2.0

Date: Sat, 25 Feb 2012 22:36:22 GMT

<?xml version="1.0" encoding="utf-8"?><Order xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"><Id>A100</Id><OrderedDate>2012-02-25T14:36:21.4774615-08:00</OrderedDate><OrderTotal>150</OrderTotal></Order>

I hope you guys find this post useful. I will be posting more content in near future. Keep playing with our bits!

Also there is a forum regarding ASP.NET Web API over here. It’s very active and post any questions that you might have.