Share via

February 2014

Volume 29 Number 2

Cutting Edge : Content Negotiation and Web API for the ASP.NET MVC Developer

Dino Esposito | February 2014

Dino EspositoOne of the things I like most in ASP.NET MVC is the ability to expose a façade of methods that can be easily invoked from HTTP clients, including jQuery-based pages, mobile apps and plain C# back ends. For a long time, building this service layer took place in the realm of Windows Communication Foundation (WCF) services. Attempts were made to specialize WCF for HTTP, such as the introduction of the webHttpBinding mechanism and frameworks such as the now-retired REST Starter Kit. None of these approaches, though, could really eliminate developer roadblocks such as notorious WCF over-configuration, overuse of attributes and a structure not specifically designed for testability. Then came Web API—a new framework designed to be thin, testable, independent from the hosting environment (for example, IIS) and HTTP-focused.

However, Web API has a programming interface that looks almost too similar to ASP.NET MVC, in my opinion. This isn’t a negative remark, though, as ASP.NET MVC has a clean and well-defined programming interface. Web API actually started with a programming model that looked similar to WCF and then grew to resemble ASP.NET MVC.

In this article, I’ll provide a view of Web API from the perspective of the average ASP.NET MVC developer, and focus on a functional area of Web API that represents a plus over plain ASP.NET MVC: content negotiation.

Web API at a Glance

Web API is a framework you can use to create a library of classes that can handle HTTP requests. The resulting library, along with some initial configuration settings, can be hosted in a runtime environment and consumed by callers via HTTP. Public methods on controller classes become HTTP endpoints. Configurable routing rules help define the form of URLs used to access specific methods. With the exception of routing, however, most of what defines the default form of URL handling in Web API is convention rather than configuration.

If you’re an ASP.NET MVC developer, at this point you might stop reading and wonder why on earth you’d want to use a new framework that seems to just duplicate the concept of controllers you “already have” in ASP.NET MVC.

The quick answer to that is, yes, you probably don’t need Web API in ASP.NET MVC, because you can achieve nearly the same functionality via plain controllers. For example, you can easily return data formatted as JSON or XML strings. You can easily return binary data or plain text. You can shape up the URL templates you like best.

The same controller class can serve JSON data or an HTML view, and you can easily separate controllers that return HTML from controllers that just return data. In fact, a common practice is to have an ApiController class in the project where you stuff all endpoints expected to return plain data. Here’s an example:

public class ApiController : Controller {
public ActionResult Customers()
  var data = _repository.GetAllCustomers();
  return Json(data, JsonRequestBehavior.AllowGet);  }

Web API uses the best of the ASP.NET MVC architecture and improves it in two main areas. First, it introduces a new logical layer known as content negotiation with a standard set of rules to request data in a given format, whether JSON, XML or some other format. Second, Web API has no dependencies whatsoever on ASP.NET and IIS—more specifically, it has no dependency on the system.web.dll library. Certainly it can be hosted in an ASP.NET application under IIS. However, while this probably remains the most common scenario, a Web API library can be hosted in any other application that provides an ad hoc hosting environment, such as a Windows service, a Windows Presentation Foundation (WPF) application or a console application.

At the same time, if you’re an expert ASP.NET MVC developer, the Web API concepts of controllers, model binding, routing and action filters will be familiar to you.

Why Web Forms Developers Love Web API

If you’re an ASP.NET MVC developer, you might be initially confused regarding the benefits of Web API because its  programming model looks nearly identical to ASP.NET MVC. However, if you’re a Web Forms developer, you shouldn’t be confused. With Web API, exposing HTTP endpoints from within a Web Forms application is a child’s game. All it takes is adding one or more classes similar to this:

public class ValuesController : ApiController
  public IEnumerable<string> Get()
    return new string[] { "value1", "value2" };
  public string Get(int id)
    return "value";

Note that this is the same code you’d use to add a Web API controller to an ASP.NET MVC application. You also have to specify routes. Here’s some code you want to run at application startup:

  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = System.Web.Http.RouteParameter.Optional });

Unless otherwise annotated with the NonAction attribute, any public methods on the class that match the default naming and routing conventions are public HTTP-callable endpoints. They can be called from any client without the need for generated proxy classes, web.config references or special code.

Routing conventions in Web API dictate the URL starts with /api followed by the controller name. Note that there’s no action name clearly expressed. The action is determined by the type of request, whether GET, PUT, POST or DELETE. A method name that begins with Get, Put, Post or Delete is conventionally mapped to the corresponding action. For example, a method GetTasks on a TaskController will be invoked for any GET request to a URL such as /api/task.

Regardless of the apparent similarity of behavior and class names with ASP.NET MVC, Web API lives in a completely separate set of assemblies and uses a completely different set of types—System.Net.Http is the primary assembly.

Inside Web API Content Negotiation

“Content negotiation” is often used to describe the process of inspecting the structure of an incoming HTTP request to figure out the formats in which the client wishes to receive responses. Technically, though, content negotiation is the process in which client and server determine the best possible representation format to use in their interactions. Inspecting the request typically means looking into a couple of HTTP headers such as Accept and Content-Type. Content-Type, in particular, is used on the server for processing POST and PUT requests and on the client for choosing the formatter for HTTP responses. Content-Type is not used for GET requests.

The internal machinery of content negotiation, however, is much more sophisticated. The aforementioned scenario is the most typical—because of default conventions and implementations—but it isn’t the only one possible.

The component that governs the negotiation process in Web API is the class called DefaultContentNegotiator. It implements a public interface (IContentNegotiator), so you can replace it entirely if needed. Internally, the default negotiator applies several distinct criteria in order to figure out the ideal format for the response.

The negotiator works with a list of registered media type formatters—the components that actually turn objects into a specific format. The negotiator goes through the list of formatters and stops at the first match. A formatter has a couple of ways to let the negotiator know it can serialize the response for the current request.

The first check occurs on the content of the MediaTypeMappings collection, which is empty by default in all predefined media type formatters. A media type mapping indicates a condition that, if verified, entitles the formatter to serialize the response for the ongoing request. There are a few predefined media type mappings. One looks at a particular parameter in the query string. For example, you can enable XML serialization by simply requiring that an xml=true expression is added to the query string used to invoke Web API. For this to happen, you need to have the following code in the constructor of  your custom XML media type formatter:

MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "text/xml"));

In a similar way, you can have callers express their preferences by adding an extension to the URL or by adding a custom HTTP header:

MediaTypeMappings.Add(new UriPathExtensionMapping("xml", "text/xml"));
MediaTypeMappings.Add(new RequestHeaderMapping("xml", "true",
  StringComparison.InvariantCultureIgnoreCase, false,"text/xml"));

For URL path extension, it means the following URL will map to the XML formatter:


Note that for URL path extensions to work you need to have an ad hoc route such as:

  name: "Url extension",
  routeTemplate: "api/{controller}/{action}.{ext}/{id}",
  defaults: new { id = RouteParameter.Optional }

For custom HTTP headers, the constructor of the RequestHeaderMapping class accepts the name of the header, its expected value and a couple of extra parameters. One optional parameter indicates the desired string comparison mode, and the other is a Boolean that indicates if the comparison is on the entire string. If the negotiator can’t find a match on the formatter using the media type mapping information, it looks at standard HTTP headers such as Accept and Content-Type. If no match is found, it again goes through the list of registered formatters and checks whether the return type of the request can be serialized by one of the formatters.

To add a custom formatter, insert something like the following code in the startup of the application (for example, in the Application_Start method):

config.Formatters.Add(xmlIndex, new NewsXmlFormatter());

Customizing the Negotiation Process

Most of the time, media type mappings let you easily fulfill any special requirements for serialization. However, you can always replace the default content negotiator by writing a derived class and overriding the MatchRequestMediaType method:

protected override MediaTypeFormatterMatch MatchRequestMediaType(
  HttpRequestMessage request, MediaTypeFormatter formatter)

You can create a completely custom content negotiator with a new class that implements the IContentNegotiator interface. Once you have a handmade negotiator, you register it with the Web API runtime:

  new YourOwnNegotiator());

The preceding code usually goes in global.asax or in one of those handy config handlers that Visual Studio creates for you in the ASP.NET MVC Web API project template.

Controlling Content Formatting from the Client

The most common scenario for content negotiation in Web API is when the Accept header is used. This approach makes content formatting completely transparent to your Web API code. The caller sets the Accept header appropriately (for example, to text/xml) and the Web API infrastructure handles it accordingly. The following code shows how to set the Accept header in a jQuery call to a Web API endpoint to get back some XML:

  url: "/api/news/all",
  type: "GET",
  headers: { Accept: "text/xml; charset=utf-8" }

In C# code, you set the Accept header like this:

var client = new HttpClient();
client.Headers.Add("Accept", "text/xml; charset=utf-8");

Any HTTP API in any programming environment lets you set HTTP headers. And if you foresee that you can have callers where this might be an issue, a best practice is to also add a media type mapping so the URL contains all the required information about content formatting.

Bear in mind that the response strictly depends on the structure of the HTTP request. Try requesting a Web API URL from the address bar of Internet Explorer 10 and Chrome. Don’t be surprised to see you get JSON in one case and XML in the other. The default Accept headers might be different in various browsers. In general, if the API will be publicly used by third parties, you should have a URL-based mechanism to select the output format.

Scenarios for Using Web API

Architecturally speaking, Web API is a big step forward. It’s becoming even more important with the recent Open Web Interface for .NET (OWIN) NuGet package (Microsoft.AspNet.Web­­Api.Owin) and Project Katana, which facilitate hosting the API in external apps through a standard set of interfaces. If you’re building solutions other than ASP.NET MVC applications, using Web API is a no-brainer. But what’s the point of using Web API within a Web solution based on ASP.NET MVC?

With plain ASP.NET MVC, you can easily build an HTTP façade without learning new things. You can negotiate content fairly easily with just a bit of code in some controller base class or in any method that needs it (or by creating a negotiated ActionResult). It’s as easy as having an extra parameter in the action method signature, checking it and then serializing the response to XML or JSON accordingly. This solution is practical as long as you limit yourself to using XML or JSON. But if you have more formats to take into account, you’ll probably want to use Web API.

As previously mentioned, Web API can be hosted outside of IIS—for example, in a Windows service. Clearly, if the API lives within an ASP.NET MVC application, you’re bound to IIS. The type of hosting therefore depends on the goals of the API layer you’re creating. If it’s meant to be consumed only by the surrounding ASP.NET MVC site, then you probably don’t need Web API. If your created API layer is really a “service” for exposing the API of some business context, then Web API used within ASP.NET MVC makes good sense.

Dino Esposito is the author of “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) and the upcoming “Programming ASP.NET MVC 5” (Microsoft Press). A technical evangelist for the .NET and Android platforms at JetBrains and frequent speaker at industry events worldwide, Esposito shares his vision of software at and on Twitter at

Thanks to the following technical expert for reviewing this article: Howard Dierking (Microsoft)
Howard Dierking is a program manager on the Windows Azure Frameworks and Tools team where his focus is on ASP.NET, NuGet and Web APIs. Previously, Dierking served as the editor in chief of MSDN Magazine, and also ran the developer certification program for Microsoft Learning. He spent 10 years prior to Microsoft as a developer and application architect with a focus on distributed systems.