Implementing message handlers to track your ASP.NET Web API usage - StrathWeb

Strath

Implementing message handlers to track your ASP.NET Web API usage

How to use DelegatingHandler in ASP.NET Web API

Today’s focus is going to be on message handlers (or, to be precise, DelegatingHandlers) in ASP.NET Web API. If you are familiar with WCF you can surely recall them – used to be called DelegatingChannels at some point – but the purpose has been the same all along, to provide the first (or last, depending whether you look at requests or responses) extendibility point in your Web API applications. You stack up as many message handlers on top of each other as you wish, and the request will travel through all of them.

This, in turn, gives us developers a possibility to process/alter/modify/decline the incoming HTTP request before it reaches the HttpControllerDispatcher. Then, when the controller creates the response, it goes through the same chain of message handlers again, so we can tamper with the response. One example of the applicability of this is that message handlers are a perfect place to address security related matters i.e. integrating OAuth.

The plan for today is to show how DelegatingHandlers are used by building a functionality that checks for an API key on an incoming API request and then logs all requests and responses, thus allowing you to track the usage of your API.

What are we going to do?

We are going to implement two DelegatingHandlers.

1. First, will deal with API key checking. Since we are going to use API Keys to log API usage, every request needs to include an API key, and this handler will ensure it. If no key is provided, the requests will not be processed further

2. Then we will build a second DelegatingHandler, which will capture all request and response data flowing in and out of ApiControllers and log them into a repository. From there, they can be viewed by Admin user.

Models

Let’s start by declaring our models first. This way later on, we can solely focus on Web API specific stuff.

We will have to deal with two types of items – HttpRequestMessage and HttpResponseMessage. Therefore I’m going to set up a base class for all the common properties and two inheriting classes. We’re gonna use primitive types all across the board (i.e. Dictionary instead of HttpHeaders collection, integer instead of StatusCode etc) so that we can easily serialize our objects later.

There is not much exciting stuff here – several properties that can be associated with both requests and responses:
– ID
– ApiKey – so that we can associate the API interaction with a given consumer
– Timestamp – when the interaction happen
– UsageType – which will indicate whether we deal with a Request or Response
– Content – the content of the Request or Response
– Headers – containing headers as key-value string/string pairs

Additionally we include a method callabale from inheriting classes to extract Headers information from HttpHeaders object to a readable and serializable dictionary.

Next, let’s design our derived classes. First Request:

We introduce three additional properties here, specific for Requests only:
– Uri – what has been requested
– RequestMethod – GET, POST, PUT,
– IP – from which IP has the request been issued

The constructor will take an HttpRequestMessage object and the API key string.

The response model looks like this:

This one, in turn, has just one type-specific proeprty, to hold the StatusCode of the response. The constructor takes an HttpResponseMessage object and the API key string.

Now, before we can say that the models are ready, we need to decorate them with some Serialization attributes. This is necessary since System.Runtime.Serialization doesn’t automatically click with inherited objects. Below is the complete code after the modifciations:

Implementing a simple repository

Now, let’s implement a simple repository to store our logged API usage. I will not play with the database here, so I’m going to dump everything into a static property which can be accessed for testing purposes. Obviously in a normal applciation you’d replace it with some data storage solution.

Interface:

And the class implementation:

As mentioned, the static instance of ConcurrentQueue will be our data repository for this exercise.

Creating the DelegatingHandlers

First let’s do the API key Handlers. As explained earlier, it’s sole purpose is to check if the request came in with an Apikey – if yes, we continue, if not we return an error to the client. Of course this is the proper place to introduce any additional key verification (i.e. matching the allowed keys and so on), but for simplicity we are not going to do that. A good reference (albeit WCF specific) can be found here in Pablo’s post.

We process the request by writing a new class inheriting from System.Net.Http.DelegatingHandler class and overriding its SendAsync method.

The handler intercepts the requests, and checks for API Key. We are using the new (introduced just last week to the source of ASP.NET Web API) , content-negotiated mechanism of returning a menaingful Error to the client through request through HttpRequestMessage. CreateErrorResponse() method.

If for some reason you can’t get this latest source to work you can create the error accordingly instead (albeit that’s not content negotiated) – up to you.

If you try to run the application now and make any ApiController request, you’d see that you get an error.

That’s because from now, any request needs to come in with ?apikey=XXX in the querysrting.

Wiring the Api Usage Handler

This is going to be surprisingly easy. We have the Models ready, we have the repository ready, and we have the first handler in place. We start off with the class dervied from System.Net.Http.DelegatingHandler, as before, and a private instance of the repo.

Now we just add the following:
– upon arrival of the request, we create a new instance of our WebApiUsageRequest, read asynchronously the Request’s body and add the item to the repo
– then we continue with the normal flow of the events (meaning the request is send back along the ASP.NET Web API pipeline)
– finally we intercept the Response, instantiate our WebApiUsageResponse and add that to the repo as well

This was fairly easy, wasn’t it?

Now we just need to register our DelegatingHandlers in the global.asax, inside Application_Start().

The important thing to remember is the order. Last added handler gets called first.

Adding a controller to view usage data

Now, just for the pure ability to test what we have done, let’s add a controller which will expose all the usage data.

We can use this controller to grab the data of API usage. Notice that since we decorated our Models carefully with appropriate serialization attributes, we can just safely return our Models (no DTO or anything like that needed).

Trying it

Let’s fire up the browser and make a few requests:
– http://localhost:50656/api/values/?apikey=testkey
– http://localhost:50656/api/values/1?apikey=differentkey
– http://localhost:50656/api/values/2?apikey=testkey

And now go to http://localhost:50656/api/admin/?apikey=adminkey to view everything that has been logged. (Note: even this request needs to come with a key!).

As you can see everything comes out nicely in JSON format (IP is showing like this since it’s running off localhost).

We can use the other method of the repository, to get all usage data for a specific key i.e. “differentkey” – in this case we navigate to http://localhost:50656/api/admin/?key=differentkey&apikey=adminkey

Finally, we can just pull one of the entries by ID – i.e.

Summary and source

Message handlers can be extremely useful and powerful tools. I hope we managed to built today something that we’ll be useful in your projects – obviously there are many directions you can go forward with this. In the meantime, let me just say that, as always the projetct’s source is available on github. Till next time!

source on github

Be Sociable, Share!

  • Pingback: Dew Drop – May 17, 2012 (#1,329) | Alvin Ashcraft's Morning Dew

  • http://www.arroyocode.com Greg

    Great post! Been looking for something similar to this for external vendor use of internal data. Api key is cool, easily assignable, manageable for limited time frame usage/subscriptions to data. Thanks for the post, enjoyed reading it.

    • Filip W

      Thanks a lot for your kind comment!

      /f

  • Website Development

    Thanks for sharing such a nice post on ASP.net as I am looking for exact thing. In ASP.net API keys are such a problematic coding but here you make it quite easy.

  • Mattias

    Very nice post, I really like it!

    Thanks

  • http://zerotoi.com Paul Elliott

    Thanks for this post, very clear, just what I was looking for. Knew something like this was possible but did not know how. Thanks again.

  • Pingback: friday links 31 « A Programmer with Microsoft tools

  • Fred

    Great Post.
    By the way, Which version of WebApi was the project build on? Beta or RC?

    • Filip W

      Thanks!

      It was built against the Nuget nightly Web API packages – so against the code that is actually even newer than RC (if I’m not mistaken against source from 5th May and RC cut off 22nd April).

      But it should work fine with RC.

  • Bab

    Thanks for this great post.

    I have a query. Is it possible to access HttpRequestMessage outside of controller, that is inside a non web api class?

    So far, I have used httpContext for setting and retrieving IPrincipal inside static helper methods.

    Ex:
    public class ContextHelper
    {
    public static int GetId()
    {
    // accessing principal details from //httpcontext user and return id details
    }
    …..
    …..
    }
    and it seems Httpcontext usage within webapi is not recommended way (as there is thread overwrite issue).

    I came to know that, access the IPrincipal via HttpRequestMessage. That’s good.

    I don’t know, how to access httpRequestMessage and it’s holding principal details inside a helper class mentioned above in the example.

  • Pingback: BitterCoder – API Implementation with Web API – Final Thoughts

  • sando
    • Filip W

      You can avoid this by removing the continuation.

      apiRequest.Content = request.Content.ReadAsStringAsync().Result;
      _repo.Add(apiRequest);

      I have updated the code accordingly.

  • Pingback: Web API Implementation – Final Thoughts | Catch Blogs

  • arsalan

    thanks

  • Citizen451

    What if there are some controllers which you do not want to require an api key? How to exclude those from the api key requirement?

  • Pingback: Pragmatic Rest with ASP C#’s Web API | Softech

  • Pingback: Pragmatic RestFull API with ASP C#’s Web API | Softech