SteGriff

Blog

Next & Previous

WebAPI with NinjectHttpApplication the new way for 2019

There’s conflicting advice on how best to integrate Ninject with ASP.Net WebAPI. You can use NinjectWebCommon.cs with WebActivatorEx to start up your injection, or you can avoid having any of that code by making your application inherit NinjectHttpApplication. This new way suits me better!

Add packages

When you add the Ninject.Web.Common package, it will still add the old NinjectWebCommon.cs file into your App_Start, but you can safely exclude/delete it from the project.

Here are the packages I’ve added (I only need Ninject.Extensions.Wcf beacuse I inject a WCF service):

<Reference Include="Ninject, Version=3.3.4.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.3.3.4\lib\net45\Ninject.dll</HintPath>
</Reference>
<Reference Include="Ninject.Extensions.Wcf, Version=3.3.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.Extensions.Wcf.3.3.0\lib\net45\Ninject.Extensions.Wcf.dll</HintPath>
</Reference>
<Reference Include="Ninject.Web.Common, Version=3.3.1.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.Web.Common.3.3.1\lib\net45\Ninject.Web.Common.dll</HintPath>
</Reference>
<Reference Include="Ninject.Web.Common.WebHost, Version=3.3.1.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.Web.Common.WebHost.3.3.1\lib\net45\Ninject.Web.Common.WebHost.dll</HintPath>
</Reference>
<Reference Include="Ninject.Web.WebApi, Version=3.3.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.Web.WebApi.3.3.0\lib\net45\Ninject.Web.WebApi.dll</HintPath>
</Reference>
<Reference Include="Ninject.Web.WebApi.WebHost, Version=3.3.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
  <HintPath>..\packages\Ninject.Web.WebApi.WebHost.3.3.0\lib\net45\Ninject.Web.WebApi.WebHost.dll</HintPath>
</Reference>

Write some code

Firstly, remove NinjectWebCommon.cs! You don’t need it!

In your Global.asax.cs file, inherit NinjectHttpApplication, and implement these Kernel setup subs, like this:

public class WebApiApplication : NinjectHttpApplication
{
    public static IKernel LocalKernel { get; set; }

    protected override IKernel CreateKernel()
    {
        // Pass in your Module setup
        var kernel = new StandardKernel(new MyModule());
        LocalKernel = kernel;

        return kernel;
    }

    protected override void OnApplicationStarted()
    {
        // Don't use a line like this - you don't need it!
        //DependencyResolver.SetResolver(new NinjectDependencyResolver(LocalKernel));
        
        // Set up my database
        Database.SetInitializer<QuoteRequestContext>(null);
        
        // Basic ASP.NET setup
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

You have to write a NinjectModule which binds your interfaces to the concrete classes which implement them. Add a class which inherits from NinjectModule and override the Load sub, like this:

public class MyModule : NinjectModule
{
    public override void Load()
    {
        Bind<IPanelDocumentationService>().To<PanelDocumentationService>();
        ...
    }
}

Your WebAPI controllers should have private interface fields for each interface you inject, and your constructor should pass them in by interface type. You don’t need an empty constructor. So your controllers look like this:

public class QuoteController : ApiController
{
    private IQuoteRequestService _quoteRequestService;
    private IAccountService _accountService;

    // No empty constructor needed!

    public QuoteController(IQuoteRequestService quoteRequestService, IAccountService accountService)
    {
        _quoteRequestService = quoteRequestService;
        _accountService = accountService;
    }

    // Actions...
}

Troubleshooting

Make sure all your dependencies line up. Make sure they all come from Nuget (look in your csproj file with a text editor) and are aligned versions. A neat way to do this is to uninstall all Ninject-related packages, then go into Package Manager, set the Dependency behaviour to ‘Highest’ and then install ‘Ninject.Web.WebApi’ first, allowing it to pull down any dependencies at their highest possible version.

If you want to inject exotic stuff, you may need the corresponding ‘Ninject.Extensions.___’ like I needed the WCF one. A runtime error will alert you to this.

Update 2019-05-08 - if you still get An error occurred when trying to create a controller of type 'SomethingController'. Make sure that the controller has a parameterless public constructor. then you may need to consider what sub-dependencies your controller’s dependencies have! Say for example, I have bound IQuoteRequestService, but it has a dependency on IQuoteDataContext and I haven’t bound that in my Kernel, I would need to add it:

public override void Load()
{
	// Thought I could get away with binding just this:
	Bind<IQuoteRequestService>().To<QuoteRequestService>().InRequestScope();
	
	// But it needs its friend in order to work :)
	Bind<IQuoteDataContext>().To<QuoteDataContext>();
}

These errors kind of ripple up so that it’s not immediately obvious why the Controller doesn’t instantiate. It might complain about some interface which you’re sure you bound, and in reality the error is because of an injected dependency of that bound type.