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.