Untitled 1
Content Negotiation in Web API
Whenever you access ASP.NET Web API from your client side script (JavaScript
/ jQuery) by default the data is returned in JSON format. However, in certain
cases you may want to retrieve the data in XML format instead of JSON. On the
server side, Web API determinses what data format to use for sending data to the
client by doing what is known as Content Negotiation. Simply put, content
negotiation is a process by which Web API inspects the incoming request and HTTP
headers accompanying the request to figure out what response format(s) the
client can understand. Based on this checking Web API sends the output. Two HTTP
headers that play role in content negotiation are:
To understand how content negotiation works let's create a simple Customer
Web API that returns customer data from the Northwind database.
Begin by creating a new ASP.NET MVC 4 project in Visual Studio 2012. You will
need to add ADO.NET Entity Framework data model for the Customers table. The
following figure shows the Customer class upon adding the data model.
Next, add a new Web API controller to the Controllers folder and name it as
CustomerController. The CustomerController needs to have just one method - Get()
- as shown below:
public class CustomerController : ApiController
{
public IEnumerable<Customer> Get()
{
NorthwindEntities db=new NorthwindEntities();
var data = (from item in db.Customers
select item).Take(10);
return data;
}
}
As you can see the Get() method simply returns first 10 Customer records from
the Customers table. To call this Web API from a client browser, add a new
controller and name it as HomeController. Then add a view for the Index() action
method of the HomeController.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
Inside the Index view, add the following jQuery code that calls the Customer
Web API:
$(document).ready(function () {
var options = {};
options.url = "/api/customer";
options.type = "GET";
options.success = OnSuccessJSON;
options.error = OnError;
$.ajax(options);
});
function OnSuccessJSON(results) {
var html = "<table border=1 cellpadding=3>";
for (var i = 0; i < results.length; i++) {
html += "<tr>";
html += "<td>" + results[i].CustomerID + "</td>";
html += "<td>" + results[i].CompanyName + "</td>";
html += "</tr>";
}
html += "</table>";
$("#container").html(html);
}
function OnError(err) {
alert(err.status + " - " + err.statusText);
}
The above code uses $.ajax() of jQuery to call the Customer Web API. The
options object stores all the settings that are needed to call our Web API.
Notice that currently we have not specified Accept and Content-Type headers. The
OnSuccessJSON() function handles the successful request and displays the
returned data in an HTML table. As mentioned earlier, by default Web API invoked
via client side script gets data from the server in JSON format. That is why the
OnSuccessJSON() function treats results object like any other JSON array. After
generating HTML markup for table the markup is set to the container <div>
element.
The OnError() function is called in case there is any error while calling the
Web API.
If you run the above view you should see the HTML table populated with
customer data as shown below:
Now let's modify our jQuery code so that the Web API sends us data in
XML format instead of JSON. Modify the options object to include Accept header
as shown below:
...
options.type = "GET";
options.headers = { "accept": "application/xml;charset=utf-8" };
...
As you can see you use the headers setting. Set its key to accept and value
to application/xml;charset=utf-8. This value tells Web API that data should be
sent in XML format. You will also need to write another success handler function
because now the data is in XML format instead of JSON. Let's call that function
OnSuccessXML().
function OnSuccessXML(results) {
var html = "<table border=1 cellpadding=3>";
$(results).find("Customer").each(function () {
var item = $(this);
html += "<tr>";
html += "<td>" + item.find("CustomerID").text() + "</td>";
html += "<td>" + item.find("CompanyName").text() + "</td>";
html += "</tr>";
});
html += "</table>";
$("#container").html(html);
}
The OnSuccessXML() function uses find() of jQuery to locate <Customer>
elements from the response XML and for each <Customer> the code specified inside
each() is executed. The each() function further finds <CustomerID> and <CompanyName>
elements from the response XML and an HTML table is generated. Finally, the
generated HTML markup is assigned to the container <div> element.
Make sure to change the success function and then run the new code:
...
options.success = OnSuccessXML;
...
In the above code you used Accept header but what's the role of Content-Type
header? The Content-Type header is used in situations where response format as
suggested by Accept header can't be sent. To understand this modify the jQuery
code as shown below:
...
options.type = "GET";
options.contentType = "application/json;charset=utf-8";
options.headers = { "accept": "application/xml123;charset=utf-8" };
...
Notice carefully that accept header contains invalid format (xml123) and
contentType setting says the format to be JSON. In this case since xml123 is an
unsupported format, Web API will use format as suggested by Content-Type header
(JSON in this case). You can confirm this by wiring OnSuccessJSON() function
again.
The following table summarizes various combinations of Accept and
Content-Type headers:
Accept |
Content-Type |
Response Format |
Yes |
No |
As per Accept header value |
Yes |
Yes |
As per Accept header value |
Yes but invalid |
Yes |
As per Content-Type header value |
No |
Yes |
As per Content-Type header value |
No or invalid |
No or invalid |
Depending on the default sequence of media formatters specified in
the Configuration.Formatters list. |
The last option from the above table can be changed via Web API code but
that's beyond the scope of this article.
That's it! Keep coding !!