Using Ninject with the latest ASP.NET Web API source

· 1000 words · 5 minutes to read

After ASP.NET Web API was beta-released in February, a number of blog posts came out explaining how to plug Ninject (and other IoC-s, for that matter) to your application through the use of the IDependencyResolver adapter. There was even a NuGet Ninject extension for that (here).

However, these approaches don’t work anymore if you are using the latest ASP.NET Web API (and release candidate) - either from Codeplex source or nightly build packages.

Let’s explore why is that and what you need to do now to be able to use Ninject with ASP.NET Web API.

Important Update: 02 June 2012 🔗

As mentioned in the comments, for the builds between 16 May and 02 June (not RC, and not any of the latest so don’t worry), there are issues with methods accepting parameters (i.e. Get(int id)). This has been raised at Codeplex here by Tim (from the comments), I added a repro project there, and turns out, as posted by Brad Wilson, that:
The issue was that we had a concrete internal type in the services container, and Ninject (and surely several other DI containers) would eagerly try to create an instance of that type when they shouldn’t have. Shifted to an internal interface instead to prevent the eager creation.

This has been modified in the ASP.NET Web Stack commit c7e396eec520. So if you are using a build from the above mentioned dates and encounter this problem, make sure to take the latest nightlies or the latest build from Codeplex. Thanks to the readers - Mark, Tim and everyone involved, and especially to Brad for having a look at this!

The old and new IDependencyResolver 🔗

The old (beta-compatible) approach for using Ninject with Web API was based on implementing a class deriving from IDependencyResolver. That interface looked like this in beta:

namespace System.Web.Http.Services  
{  
public interface IDependencyResolver  
{  
object GetService(Type serviceType);  
IEnumerable<object> GetServices(Type serviceType);
}
}

However, that has changed, and in the current version of Web API (and, as far as I know, the same will be in the release candidate), this interface is as follows:
```csharp
namespace System.Web.Http.Dependencies
{
public interface IDependencyResolver : IDependencyScope, IDisposable
{
IDependencyScope BeginScope();
}
}
```

With IDependencyScope being:
```csharp
namespace System.Web.Http.Services
{
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable

<object>
  GetServices(Type serviceType);<br /> }<br /> }<br /> ```</p> 
  
  <p>
    And <em>IDisposable</em>, obviously:<br /> ```csharp


public interface IDisposable
{
void Dispose();
}
```

  <p>
    All the Ninject dependency resolvers targeted at beta will not work now, because there are a couple more interfaces and methods that need to be implemented and catered for. The change is very well explained by Mike Wasson <a href="http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver">here</a>. Let's use his Unity example to provide support for Ninject.
  </p>
  
  <p>
    We'll need two classes - one that implements <em>IDependencyScope</em> and the other that implements.
  </p>
  
  <h3>
    NinjectScope : IDependencyScope
  </h3>
  
  <p>
    This is our scope container - think of it as a child scope. Our <em>NinjectScope</em> class is going to implement <em>IDependencyScope</em>.
  </p>
  
  <p>
    ```csharp


public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;

  <p>
    public NinjectScope(IResolutionRoot kernel)<br /> {<br /> resolutionRoot = kernel;<br /> }
  </p>
  
  <p>
    public object GetService(Type serviceType)<br /> {<br /> IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);<br /> return resolutionRoot.Resolve(request).SingleOrDefault();<br /> }
  </p>
  
  <p>
    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 /> }<br /> ```<br /> We are going to use this to get service of specific type. To adhere to the requirements of <em>IDependencyScope</em>, we implement <em>IDisposable</em>. To resolve the dependencies, we use <em>IRequest</em>, to avoid depndency on <em>ResolutionExtensions</em>.
      </p>
      
      <h3>
        NinjectResolver : NinjectScope, IDependencyResolver
      </h3>
      
      <p>
        This is going to be our entry point. Think of it as global scope, which will be responsible for passing the activation block to the child scope.
      </p>
      
      <p>
        ```csharp


public class NinjectResolver : NinjectScope, IDependencyResolver
{
private IKernel _kernel;
public NinjectResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
```

      <p>
        We implement <em>IDependencyResolver</em> here, and the rest of the interface is catered for by the fact that we inherit from our previously created <em>NinjectScope</em>.
      </p>
      
      <p>
        Now things are ready to roll.
      </p>
      
      <h3>
        Enabling it in the web application
      </h3>
      
      <p>
        So, if you have <strong>Ninject.MVC3</strong> added to you solution, you'd go to <em>NinjectWebCommon.cs</em> (or <em>Global.asax</em>, depending on you activation preferences) and would add this (after you register your services):
      </p>
      
      <p>
        [crayon lang="sharp"]<br /> GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);<br /> ```
      </p>
      
      <p>
        Please note that from the Web API Beta, the configuration changed its place and type, as it's now a property of <em>GlobalConfiguration.Configuration</em>.
      </p>
      
      <h3>
        Trying it out
      </h3>
      
      <p>
        In my case I have a simple pair of <em>IUrlRepository</em> and <em>UrlRepository</em>. It's the same stuff I used <a href="/2012/04/rss-atom-mediatypeformatter-for-asp-net-webapi/">here</a> before.
      </p>
      
      <p>
        So I register the service:<br /> ```csharp


private static void RegisterServices(IKernel kernel)
{
kernel.Bind().To();
}
```

      <p>
        And then set up my <em>ApiController</em>:<br /> ```csharp


public class ValuesController : ApiController
{
private readonly IUrlRepository _repo;
public ValuesController(IUrlRepository repo)
{
_repo = repo;
}
public IQueryable Get()
{
return _repo.GetAll();
}
}
```

      <p>
        Now I can fire up the controller, and voila:
      </p>
      
      <p>
        <a href="/images/2012/05/ninject-webapi.png"><img class="aligncenter size-large wp-image-269" title="ninject-webapi" src="/images/2012/05/ninject-webapi-1024x551.png" alt="" width="584" height="314" /></a>
      </p>
      
      <p>
        IoC with Ninject, running smoothly with ASP.NET Web API!
      </p>
      
      <h3>
        Source code
      </h3>
      
      <p>
        I put up source code for the two classes on github (no point in adding entire project). It would make sense that this is merged into <em>Ninject.Web.WebAPI</em> on Nuget, but since that project is dependent on ASP.NET Web API (the NuGet version), I guess it won't happen until ASP.NET Web API RC is available on Nuget (unless that dependency is removed).
      </p>
      
      <p>
        Anyway, till next time!
      </p>
      
      <p>
        - <a href="https://github.com/filipw/Ninject-resolver-for-ASP.NET-Web-API">source on GitHub</a>
      </p>

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 and on Mastodon.

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