Tapping into ASP.NET Web API 2

In this blog post, you will learn how to implement an HTTP-based web service for a book store. The focus here is to log the information on query-objects from incoming HTTP requests and outgoing HTTP responses before they get delivered to the client. We also want to make sure that it allows versioning. Now, the question is, what framework are we going to use?

Why Web API?

In a web services world, XML-RPC (Remote Procedure Call) and SOAP (Simple Object Access Protocol) used to be the two leading protocols for API design. There has been hype about RESTful (Representational State Transfer) APIs lately because, in addition to its resource-oriented structure, you will find that it is highly-maintainable, lightweight and simple. Besides, when we want data-centric operations like CRUD, we would prefer Web API controllers for serving JSON-based RESTful clients.

The reason why WCF (Windows Communication Foundation) is not chosen here is that we want to keep the possibility of using OWIN self-hosting and make the service accessible from a wide variety of HTTP clients. Based on these basic requirements, a sample project will now be created using ASP.NET Web API 2 and .NET 4.5.

Bird’s-eye View

Before we start the construction from the scratch, we need to know what type of pillars to use and what kind of design plans to apply for the building block. For any project’s foundation, unit tests acts as the pillars as they can detect the code modifications soon enough to escalate the missing validations and business logic. With that in mind, a design pattern that compliments the readiness of unit testing is the Dependency Injection (DI) pattern which not only decouples the class objects and modules but also favors the famous SOLID principle. Out of today’s popular Dependency Injection Containers such as Ninject, StructureMap, Windsor and Unity, for this sample project, we will select the Unity. Unity container is a lightweight extensible dependency injection container that allows constructor, property, and method call injections supported by Microsoft Patterns and Practices.

Dependency Resolver

For the sample project, we first create an ASP.NET Web Application project with Web API framework. Then, we install the Unity NuGet package in the target project to wire up the dependencies. After that, we have to make sure that the ASP.NET Web API recognizes the Unity as its default DI container.

Before proceeding, let’s take a look at the System.Web.Http that comes in with the Web API 2 package. It has the GlobalConfiguration class object where you can edit the HttpConfiguration for custom route handlers, filters, formatters and dependency resolvers. The HttpConfiguration accepts a DependencyResolver object to resolve dependencies. Since our dependency resolver is the Unity, we create a custom dependency resolver called UnityResolver to implement the IDependencyResolver.

If we look at the IDependencyResolver interface, it declares a method called BeginScope and the two interfaces that it is deriving from: IDendencyScope and IDisposable declare GetService, GetServices and Dispose methods respectively.

The BeginScope method creates a new instance of the container to resolve and releases objects that belong to the UnityResolver dependency scope for the lifetime of the request.

015

As a container-resolver, the UnityResolver must retain a value of the required container which in our case is the UnityContainer that implements IUnityContainer from Microsoft.Practices.Unity assembly. Then, in Application_Start method, a new UnityResolver is instantiated and assigned as the web application’s default DependencyResolver.

014

API Versioning

Let’s move onto API Versioning. Versioning comes into play when we want to keep the same host to return the different resources for the same product type query. The four different ways to back API Versioning are:

1) header-based by adding a header value,

2) URI-parameter-based by appending a query value,

3) content negotiation by including version information in Accept Header, and

4) URI in path.

As we are to follow the RESTful API Design, we will adopt simple URI-in-path method to have a segment – “v” for version with ordinal number postfix in the route path:

www.techbyte.com/api/v1/books and www.techbyte.com/api/v2/books. The only difference we see here is the version number.

Web API HTTP Message Lifecycle

We now know which API versioning method we will use. But we do not yet know how to make the Web API pipeline understand the versions so that it will send the requests to the relevant route controllers. Let’s try to understand the lifecycle of an HTTP request by checking out this poster.

poster

HttpControllerDispatcher

As you see in the above diagram, before hitting the dedicated controller, an HttpRequestMessage object has to meet with Http Message Handlers in the message processing pipeline. The HttpRoutingDispatcher relays a route-match to an attached HttpMessageHandler if it exists. If no HttpMessageHandler is attached to the matched route, the HttpRoutingDispatcher delegates it to the IHttpControllerSelector, which also is a message handler, to select the controller type. In the above diagram, you will also notice the IHttpControllerActivator which is responsible for creating or activating the selected controller type.

IHttpControllerSelector

The IHttpControllerSelector has a method called SelectController that returns the HttpControllerDescriptor object. The HttpControllerDescriptor carries the properties such as ControllerName, ControllerType, HttpConfiguration, etc., with it. For API versioning, we are going to make use of this SelectController method to return the correct controller name and type for any incoming versioned-routes.

Namespace and Controllers

To accept the following requests with versions in the URI path

/api/v1/books/1 & /api/v2/books/1

we are going to create two separate controllers in the folder, Controllers, with different namespaces:

TechBytes.Web.Controllers.V1 and

TechBytes.Web.Controllers.V2

003

In the Web API framework, the DefaultHttpControllerSelector acts as a default message handler and it is registered as an IHttpControllerSelector service handler in the HttpConfiguration. Now, that will be replaced with a new instance of VersionControllerSelector which implements the IHttpControllerSelector.

006

The VersionControllerSelector gets all the available controller types from the current assembly and assigned them to the key-value pair list with {version}.{controller name} as keys when it is initialized. Then, when the SelectController method is called, it checks the version route data from the HttpRequestMessage based on the declared routing maps.

005

Action Filters

As a reminder, the requirement of the sample project is to create a logger that records the incoming HTTP requests and outgoing HTTP responses before being processed by the controller methods. This is the time Action Filters get attention. Action Filters are invoked twice, before and after the controller action by overwriting the methods OnActionExecuting and OnActionExecuted.

The LogActionFilter class is created and derived from the ActionFilterAttribute class. Then in the overridden methods OnActionExecuting and OnActionExecuted, the instantiated logging object, IRecorder (MyRecorder), is used to record the action arguments.

013

If you look at IRecorder you will see [Dependency] attribute on it. It is to indicate that IRecorder dependency object is to be resolved by the Unity container.

008

The following displays how the custom action filter can be added to the Controller method.

010

If we build the project at this point and send the request, /api/v1/books/1, it will throw exception in OnActionExecuting at the line where MyRecorder object is referenced. It is because the Web API does not understand the existence of the IRecorder object in the LogActionFilter.

IFilterProvider

IFilterProvider has the GetFilters method which returns all the available filters in the project. To get the Unity container to be on the same page with the Web API’s HttpConfiguration, we create a custom IFilterProvider, LogActionFilterProvider, which calls the Unity’s BuildUp method to inject the dependencies to the filters in the GetFilters method.

011

Then, we need to replace the default IFilterProvider with the LogActionFilterProvider in HttpConfiguration object.

007

Now, if you run the project in localhost and send GET requests for http://localhost:49410/api/v1/books/1,

postman01

and http://localhost:49410/api/v3/books/1,

postman02

you will get different results.

Now, check the Output window in the Visual Studio to see if the logger, MyRecorder, is actually logging the events.

vs01

Summary

In this article, we’ve seen the capability of IHttpControllerSelector message handler and action filters to modify the route data and controller action methods. The role of Dependency Injection is also highlighted to show its benefits in Web API projects.

Please check out more on https://github.com/OThanda/techbyte001 for the complete sample project.

Leave a Reply