ASP.NET Web API and dependencies in request scope - StrathWeb

Strath

November 14th, 2012

ASP.NET Web API and dependencies in request scope

Because in request scope is easy to do with Web API

Regardless of what types of applications you are building with Web API, sooner or later you will run into a situation where you need to scope certain dependencies to the lifetime of a web request.

Examples of these types of in request scope dependencies could be loggers, unit of work implementations, NHibernate session, RavenDB session, Mindscape Lightspeed UnitOfWork or many other. Fortunately, this is very easy to do with Web API and an IoC container.

More after the jump.

Sample scenario of in request scope

Let’s start with a sample scenario – imagine some sort of an abstract UnitOfWork (the actual concrete implementation is not important, we will mainly focus on dealing with dependency lifetime).

Our implementation which we will use for testing is simply going to expose a unique session ID created when the UoW is first injected. We can then track that ID – to make sure whether the dependency is really scoped to the lifetime of the request and not re-created.

Using IoC

Let’s use Ninject to do the dependency resolution for us. I blogged about creating the Web API resolver for Ninject some time ago, and we’ll use this code.

This is registered against GlobalConfiguration:

Enter Web API

So let’s say you want to use your UnitOfWork inside an action filter attribute (to commit after the action executes – very common scenario) and, obviously, inside the controller. The scope of the unit of work has to be the same in order for the commit to succeed.

Because it is not possible to constructor-inject a dependency into an ActionFilter, you have to use property injection or, more conveniently in our case, resolve from the Ninject DependecyResolver we just created.

Most of the online tutorials will show this code to use in order to resolve a dependency from the DependencyResolver:

This is totally fine, except that this will create a new dependency scope for you (!), meaning that the UnitOfWork resolved like this inside a filter will be a different instance from the UnitOfWork resolved through the controller constructor injection.

In order to keep the dependency resolution in request scope we have to use a nice and useful, yet little know extension method on the HttpRequestMessageGetDependencyScope(), more about which you can read up on MSDN.

This allows us to access common scope for a request from anywhere where we deal with the request object – MessageHandler, ActionFilter, Controller, even MediaTypeFormatters!

Demo

Here is an example. Let’s create a commit action filter:

We obtain the UnitOfWork from our DependencyResolver in two ways:
– from GlobalConfiguration
– using the GetDependencyScope() extension method
and log its SessionId in the trace.

Then let’s add a controller:

Controller takes the same UnitOfWork dependency and also logs the SessionID. Our Action filter kicks in upon post, as you’d expect such attribute to work; once the request is completed we’d commit.

We can run this example:

And we see that both UnitOfWork inside ActionFilter retrieved off a Request object and a Controller-level UnitOfWork share the same session ID, so they are the same object instance, while the one we resolved from GlobalConfiguration is different.

As I said, we can continue using our in request scope dependency resolution anywhere; for example in the MessageHandler:

Since handlers are the first & last things that run in the Web API pipeline, they happen to be the earliest and the last possible points where we can access a given injected dependency.

Again, as you see, the SessionId is the same across the board. Note that this is very useful, since due to the nature of the MessageHandler’s lifecycle (created once per app not once per request) it’s also not possible to inject dependencies into it with a constructor.

Finally, a very cool this is that you don’t have to worry about disposing of the dependencies. Web API takes care of it by calling its own extension method, DisposeRequestResources at the end of the request lifetime. This then makes sure to call Dispose on all tracked resources.

Summary

Web API, through a combination of its IDependencyResolver interface and the GetDependencyScope() extension method allows us to easily manage resources in request scope. In our case we use Ninject to resolve the dependencies, but you might have used any other IoC container as long as you’d plug it into Web API.

There are many useful application scenarios for this particular mechanism and hopefully you will find this helpful

Be Sociable, Share!

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1233

  • Pingback: Dew Drop – November 15, 2012 (#1,443) | Alvin Ashcraft's Morning Dew

  • James Manning

    I haven’t actually used WebAPI yet (let alone with Ninject), but I would have guessed that you could just use nuget and install the Ninject.Web.WebApi (http://nuget.org/packages/Ninject.Web.WebApi) ? In particular, AFAICT you could then use its InRequestScope() support (like the rest of Ninject.Web.* supports) ?

    My apologies if this doesn’t work or I’m missing something, but wanted to pass along since, at least based on the description, it seems to add the ninject support (including request scope) for you.

    Thanks!

    • http://www.strathweb.com/ Filip W

      James, that package is long outdated – it was written against Web API Beta, and didn’t work against Web API RC already, not to mention Web API RTM :)

      • jamesmanning

        ah, ok – good to know. Happen to know enough about the changes that you could either do a pull request or share what changed and I can take a crack at it? :) Thanks!

        • jamesmanning

          Looks like a temporary package ‘Ninject.Web.WebApi-RC’ (the description says it supports RTM) was made/updated today, so hopefully RSN Remo will have the ‘real’ one updated as necessary.

          https://nuget.org/packages/Ninject.Web.WebApi-RC/3.0.0.22

          • João Acabado

            Hi James, just to warn it doesn’t work as well as it should. I got it to work whenever I had the proper Binding configurations but it went havoc when Bindings were badly thought. I am using this method here to have ninject working ok with WebApi and ActionFilters.

  • Dan Sargeant

    Was just about throw the computer out of the window when I came across this. Saved me the cost of a new one! Could not figure out why I was getting two different nhibernate sessions and the dependency scope was the answer. Thanks

    • http://www.strathweb.com/ Filip W

      haha, thanks

  • Patrick McCoy

    Does you “GetServices” method work. It does not seem to return multiple instances.

  • Vishwanath Kenchanagoudar

    Hello Filip . Why do we need the service and the webapi both together . I am having a similar problem with the webapi where i could not get hold of the Nhibernate session . Am new to WebApi and Nhibernate . I have used the same global.asax file to start the session but yet the session object is always null . Please help