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?


Ready to Learn Vue with ASP.NET Core?

My new Wilder Minds' course is available as an Early Access for only $79. It will be released on a weekly basis. The first module is now available:

Enroll Today


Shawn
Shawn Wildermuth
Author, Teacher, and Coach




My Courses

Wilder Minds Training
Vue.js by Example (Now Available)
Bootstrap 4 by Example
Intro to Font Awesome 5 (Free Course)
Building a Web App with ASP.NET Core, MVC6, EF Core, Bootstrap and Angular (updated for 2.1)
Using Visual Studio Code for ASP.NET Core Projects
Implementing ASP.NET Web API
Web API Design
JavaScript for C# Developers

Application Name WilderBlog Environment Name Production
Application Ver v4.0.30319 Runtime Framework x86
App Path D:\home\site\wwwroot\ Runtime Version .NET Core 4.6.26814.03
Operating System Microsoft Windows 10.0.14393 Runtime Arch X86