ASP.NET Web API and dependencies in request scope

Β· 1214 words Β· 6 minutes to read

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).

public interface IUnitOfWork  
{  
Guid SessionId { get; }  
void Commit();  
}  

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.

public class UnitOfWork : IUnitOfWork  
{  
public UnitOfWork()  
{  
SessionId = Guid.NewGuid();  
}

public Guid SessionId { get; private set; }  
public void Commit()  
{  
//irrelevant  
}  
}

Using IoC πŸ”—

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

public class NinjectScope : IDependencyScope  
{  
protected IResolutionRoot resolutionRoot;

public NinjectScope(IResolutionRoot kernel)  
{  
resolutionRoot = kernel;  
}

public object GetService(Type serviceType)  
{  
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);  
return resolutionRoot.Resolve(request).SingleOrDefault();  
}

public IEnumerable

<object>
  GetServices(Type serviceType)<br /> {<br /> IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);<br /> return resolutionRoot.Resolve(request).ToList();<br /> }</p> 
  
  <p>
    public void Dispose()<br /> {<br /> IDisposable disposable = (IDisposable)resolutionRoot;<br /> if (disposable != null) disposable.Dispose();<br /> resolutionRoot = null;<br /> }<br /> }
  </p>
  
  <p>
    public class NinjectResolver : NinjectScope, IDependencyResolver<br /> {<br /> private IKernel _kernel;<br /> public NinjectResolver(IKernel kernel)<br /> : base(kernel)<br /> {<br /> _kernel = kernel;<br /> }<br /> public IDependencyScope BeginScope()<br /> {<br /> return new NinjectScope(_kernel.BeginBlock());<br /> }<br /> }<br /> ```
  </p>
  
  <p>
    This is registered against <i>GlobalConfiguration</i>:<br /> ```csharp
<br /> kernel.Bind<IUnitOfWork>().To<UnitOfWork>();<br /> GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);<br /> ```
  </p>
  
  <h3>
    Enter Web API
  </h3>
  
  <p>
    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.
  </p>
  
  <p>
    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.
  </p>
  
  <p>
    Most of the online tutorials will show this code to use in order to resolve a dependency from the <i>DependencyResolver</i>:<br /> ```csharp
<br /> var uow = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnitOfWork)) as IUnitOfWork;<br /> ```
  </p>
  
  <p>
    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 <strong>a different instance</strong> from the UnitOfWork resolved through the controller constructor injection.
  </p>
  
  <p>
    In order to keep the dependency resolution <strong>in request scope</strong> we have to use a nice and useful, yet little know extension method on the <i>HttpRequestMessage</i> - <i>GetDependencyScope()</i>, more about which you can <a href="http://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessageextensions.getdependencyscope(v=vs.108).aspx">read up on MSDN</a>.
  </p>
  
  <p>
    This allows us to access common scope for a request from anywhere where we deal with the request object - MessageHandler, ActionFilter, Controller, even MediaTypeFormatters!
  </p>
  
  <h3>
    Demo
  </h3>
  
  <p>
    Here is an example. Let’s create a commit action filter:<br /> ```csharp
<br /> public class UnitOfWorkCommitAttribute : ActionFilterAttribute<br /> {<br /> public IUnitOfWork UoW {get; set;}
  </p>
  
  <p>
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)<br /> {<br /> UoW = actionExecutedContext.Request.GetDependencyScope().GetService(typeof(IUnitOfWork)) as IUnitOfWork;<br /> System.Diagnostics.Trace.WriteLine("Scoped UoW " + UoW.SessionId);
  </p>
  
  <p>
    //Uow.Commit(); here you would commit
  </p>
  
  <p>
    UoW = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnitOfWork)) as IUnitOfWork;<br /> System.Diagnostics.Trace.WriteLine("GlobalConfig UoW " + UoW.SessionId);<br /> }<br /> }
  </p>
  
  <p>
    ```
  </p>
  
  <p>
    We obtain the UnitOfWork from our <i>DependencyResolver</i> in two ways:<br /> - from GlobalConfiguration<br /> - using the <i>GetDependencyScope()</i> extension method<br /> and log its <i>SessionId</i> in the trace.
  </p>
  
  <p>
    Then let’s add a controller:<br /> ```csharp
<br /> public class ValuesController : ApiController<br /> {<br /> private IUnitOfWork _uow;
  </p>
  
  <p>
    public ValuesController(IUnitOfWork uow)<br /> {<br /> _uow = uow;<br /> System.Diagnostics.Trace.WriteLine("Controller-level UoW " + uow.SessionId);<br /> }
  </p>
  
  <p>
    [UnitOfWorkCommit]<br /> public void Post(MyType mt)<br /> {<br /> //do stuff<br /> }<br /> }<br /> ```
  </p>
  
  <p>
    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.
  </p>
  
  <p>
    We can run this example:
  </p>
  
  <p>
    <a href="/images/2012/11/output.png"><img src="/images/2012/11/output.png" alt="" title="output" width="426" height="106" class="aligncenter size-full wp-image-662" srcset="/images/2012/11/output.png 426w, /images/2012/11/output-300x75.png 300w" sizes="(max-width: 426px) 100vw, 426px" /></a>
  </p>
  
  <p>
    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 <i>GlobalConfiguration</i> is different.
  </p>
  
  <p>
    As I said, we can continue using our in request scope dependency resolution anywhere; for example in the <i>MessageHandler</i>:<br /> ```csharp
<br /> public class PerRequestScopeHandler : DelegatingHandler<br /> {<br /> public IUnitOfWork UoW { get; set; }
  </p>
  
  <p>
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)<br /> {<br /> UoW = request.GetDependencyScope().GetService(typeof(IUnitOfWork)) as IUnitOfWork;<br /> System.Diagnostics.Trace.WriteLine("Scoped UoW Begin Request" + UoW.SessionId);
  </p>
  
  <p>
    return base.SendAsync(request, cancellationToken).ContinueWith(t => {<br /> UoW = request.GetDependencyScope().GetService(typeof(IUnitOfWork)) as IUnitOfWork;<br /> System.Diagnostics.Trace.WriteLine("Scoped UoW End Request" + UoW.SessionId);
  </p>
  
  <p>
    return t.Result;<br /> });<br /> }<br /> }<br /> ```
  </p>
  
  <p>
    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.
  </p>
  
  <p>
    <a href="/images/2012/11/output_unit_of_work_scope.png"><img src="/images/2012/11/output_unit_of_work_scope.png" alt="" title="output_unit_of_work_scope" width="450" height="123" class="aligncenter size-full wp-image-663" srcset="/images/2012/11/output_unit_of_work_scope.png 450w, /images/2012/11/output_unit_of_work_scope-300x82.png 300w" sizes="(max-width: 450px) 100vw, 450px" /></a>
  </p>
  
  <p>
    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.
  </p>
  
  <p>
    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, <i>DisposeRequestResources</i> at the end of the request lifetime. This then makes sure to call <i>Dispose</i> on all tracked resources.
  </p>
  
  <h3>
    Summary
  </h3>
  
  <p>
    Web API, through a combination of its IDependencyResolver interface and the <i>GetDependencyScope()</i> 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.
  </p>
  
  <p>
    There are many useful application scenarios for this particular mechanism and hopefully you will find this helpful
  </p>

 [1]: /2012/05/using-ninject-with-the-latest-asp-net-web-api-source/

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP