WebAPI and Ninject

Traffic accident and to drivers fightingI will be returning to my 10 part series on Modern Web Development soon, but I have a quickie post that hopefully will help some of you.

In my main project, I am using Ninject to inject dependencies into Controllers. This works really well and I won’t belabor how that works here (see project here for how to get via Nuget and how-tos).

For me, Dependency Injection (or IoC) is a commodity. Ninject does a great job so I use. I could be using SM, Unity or a host of other DI/IoC solutions and it probably wouldn’t matter too much. So, this is to just short circuit the “Why didn’t you use my favorite IoC” questions.

The Problem

In a web project I am working on, Ninject is bootstrapped to provide controllers with resources (usually in the constructor) via Ninject.MVC Nuget package. Inside the Bootstrapper for Ninject, it sets Ninject as the DependencyResolver so that ASP.NET MVC’s Controller factory will know how to resolve missing dependencies. This works great and has been for some time.

Enter WebAPI Beta (that was shipped with MVC4 Beta) that I am using to create a publically available API. Everything was great until I created an API Controller that required dependencies (services) like so:

  public class ApiAuthController : ApiController
  {
    readonly IMembershipService _membership;

    public ApiAuthController(IMembershipService membership)
    {
      _membership = membership;
    }

Creating this controller failed because the Web API stack and the MVC stack are completely separate. This is confusing to some as they were announced together, but a prevailing theme of this stack was to be completely independent. This means it doesn’t have access to the DependencyResolver from System.Web.Mvc.

To address this, the Web API stack has a way to set the configuration’s resolver:

// Set Web API Resolver
GlobalConfiguration.Configuration
                   .ServiceResolver
                   .SetResolver(...);

The SetResolver method takes one of three things:

  • An instance of IDependencyResolver
  • A Function pointer (Func<>) to the GetService and GetServices methods of a resolver
  • An instance of CommonServiceLocator (see adapters here).

For my need it seemed, obvious. Looking a the IDependencyResolver interface, MVC’s DependencyResolver class (which Ninject wired up for me) implements the IDependencyResolver.  Great…but it didn’t work:

// Set Web API Resolver
GlobalConfiguration.Configuration
                   .ServiceResolver
                   .SetResolver(DependencyResolver.Current);

The reason this didn’t work took some digging. The reason is that the WebAPI stack was expecting an instance of System.Web.Http.Services.IDependencyResolver and the DependencyResolver.Current is an instance of the System.Web.Mvc.IDependencyResolver. Ick.

So after complaining on Twitter, I decided to do this as it should work:

// Set Web API Resolver
GlobalConfiguration.Configuration
                   .ServiceResolver
                   .SetResolver(DependencyResolver.Current.GetService,
                                DependencyResolver.Current.GetServices);

This works, but I felt dirty.

Brad Wilson (@bradwilson) is on the WebAPI team and he scoffed (correctly) at my suggestion that it should just support duck typing of the GetService, GetServices methods. He suggested I used the third overload where it is using the CommonServiceLocator adapter.

CommonServiceLocator is an interface for dependency injection that all vendors can implement. I fired up Nuget and found the Ninject CommonServiceLocator adapter:

2-26-2012 4-06-02 AM

Once I had this installed, I could wire this up directly in the Ninject bootstrapper:

using NinjectAdapter;

public static class NinjectMVC3
{
  static readonly Bootstrapper bootstrapper 
    = new Bootstrapper();

  public static void Start()
  {
    DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
    DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));

    bootstrapper.Initialize(CreateKernel);

  }

  ...

  static IKernel CreateKernel()
  {
    var kernel = new StandardKernel();

    // Register Dependencies
    RegisterServices(kernel);

    // Set Web API Resolver
    GlobalConfiguration.Configuration
                       .ServiceResolver
                       .SetResolver(new NinjectServiceLocator(kernel));

    return kernel;
  }
  ...
}

I just wrapped the IKernel object with the NinjectServiceLocator (which is a CommonServiceLocator adapter) in the NinjectAdapter namespace. This creates an instance of the CSL for the Ninject Kernel. Done.

Hopefully this will be a case of “It’s easy once you know how!”.

What do you think?

 

Comments

Gravatar

Radenko Zec Sunday, February 26, 2012

Hi there. Nice post.
I think most easier way to wire up Ninject inside Asp.Net Web Api without any third-party dll-s is like in Microsoft Contact Manager example :
var kernel = new StandardKernel();
kernel.Bind<IContactRepository>().ToConstant(new ContactRepository());
...
config.ServiceResolver.SetResolver(
t => kernel.TryGet(t),
t => kernel.GetAll(t));

You can further refactor this by extracting registrations to other class and method...

Gravatar

Shawn Wildermuth Sunday, February 26, 2012

Radenko,

This is pretty much to what I was doing in the sending in the GetService/GetServices implementation. I just feel dirty using that method. But for some it might be the right solution. Thanks!

Gravatar

Aaron Fischer Sunday, February 26, 2012

I might be missing something but couldn't you have used dynamic to lie about the type? Assuming the interfaces method signature is the same?

Gravatar

Derik Whittaker Sunday, February 26, 2012

Shawn,

Ha, i was just working on a post to show a very similar way to do this :) I know what we were both working on/playing with today.

Gravatar

Shawn Wildermuth Sunday, February 26, 2012

Aaron,

Sure you could have, but that feels very hacky to me. But that's just me.

Gravatar

Shawn Wildermuth Sunday, February 26, 2012

Javvin,

Perhaps, but I think there is too heavily reliance on IoC as a "must have for any architecture". It still needs to be pragmatic. I think it works so well in MVC because we're not creating the views so dependency management becomes difficult, the IoC helps the containers not have to go find their own factories which is why I use it here. I tend to rarely use it in WP and more so for larger apps (e.g. WPF, SL). For XAML-based Metro, it might be a good idea but GooNews isn't big so don't hold your breath. Also, I'll probably build GooNews for Metro twice to see the differences in how the HTML/XAML stack are.

At the end of the day, being dogmatic is what I am trying to avoid...and assuming that IoC/DI as a requirement for any type of development is dogmatic IMO.

Gravatar

James Manning Sunday, February 26, 2012

FWIW, the 2 different IDependencyResolver interfaces are warned about in Chapter 6 of the Web API overview.

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

Web API uses the IDependencyResolver interface that is defined in the System.Web.Http.Services namespace. The System.Web.Mvc namespace also contains an IDependencyResolver, so be careful to implement the right interface type.

Gravatar

Andrew Webb Monday, February 27, 2012

Am using Radenko's method, and to me it feels very simple and clean.

Gravatar

C Tuesday, February 28, 2012

I get this:
Activation error occured while trying to get instance of type IActionValueBinder, key ""

Gravatar

Bilal Hasan Khan Sunday, March 04, 2012

Hi Shawn,

I am getting ILogger error when implementing Ninject as suggested by you.

regards

Bilal

Gravatar

Shawn Wildermuth Monday, March 05, 2012

C, Bilal and Matt,

This is working for me flawlessly. I don't know the nature of your issues.

Gravatar

Nuno Costa Monday, May 07, 2012

C, Bilal, Matt

I'm also getting the ILogger errors!
I've changet Shawn .SetResolver(new NinjectServiceLocator(kernel)); line to the one sugested by Radenko and it worked!

.ServiceResolver.SetResolver(
t => kernel.TryGet(t),
t => kernel.GetAll(t));


Gravatar

RyanonRails Wednesday, May 16, 2012

This is great post. It explained the root cause, and a quick and easy solution.

There's always 100 ways to fix a problem, I just want the one that's quickest to move me along.

Thanks Shawn!

Gravatar

jernej Monday, June 04, 2012

I have just updated ASP.NET Web Stack packages via NuGet (nightly 2012 jun 01). It seems that the ServiceResolver property does not exist anymore so the following code will not compile:

// Set Web API Resolver
GlobalConfiguration.Configuration
.ServiceResolver
.SetResolver(new NinjectServiceLocator(kernel));


Gravatar

jernej Monday, June 04, 2012

Here is the solution but I'm not sure how to implement it
http://forums.asp.net/p/1807570/4997977.aspx/1?Re+Weird+compiler+error

Gravatar

Steve Chalmers Tuesday, February 12, 2013

The resolver line appears to work with MVC4 Beta.
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(...);
For those reading this using the release I changed it to the following
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
Uses Brad Wilson Ninject DependencyResolver code at https://gist.github.com/2417226


Leave a Comment

*
*
*

Search Blog

My Courses

pluralsight

Ready to start building Windows Phone 8 Applications? This is the book for you. I teach you how to build apps using Windows Phone 8. Order today!

Have the book? You can get the downloads and errata here.

Hosting provided by:

Windows Cloud Server Hosting