Simple Injector unable to inject dependencies in Web API controllers
TLTR: the problem is caused by the implicit way Web API handles resolving controller types; register your Web API controllers explicitly and you'll see where the problem is.
Here is a step by step what is happening under the covers:
- The
System.Web.Http.DefaultHttpControllerActivator
calls into theSimpleInjectorWebApiDependencyResolver
and requests the creation of an API controller. SimpleInjectorWebApiDependencyResolver
forwards that call to theSimpleInjector.Container
instance.- That
Container
instance however, does not have any explicit registrations for that API Controller (since you supplied an empty container to the resolver). - Since there is no explicit registration, the container tries to do a last minute registration for that type.
- That Controller type however depends on interfaces that can't be resolved because they are not registered in the container (remember, your container is empty).
- Although the container would normally throw an exception, null is returned in this case, because the type is requested through the
IServiceProvider.GetService
method and the type was not registered explictly. - The
SimpleInjectorWebApiDependencyResolver
'sGetService
method will returnnull
as well, since it's by definition that it should return null; It should return null when no registration exists (which currently is the case). - Since the
DependencyResolver
returned null,DefaultHttpControllerActivator
will fall back to its default behavior, which means creating that type itself, but this requires the controller to have a default constructor.
Long story short, the problem is caused by the implicit way Web API handles resolving controller types.
So the solution here is to:
- Have only one single
Container
in your web application. This prevents all sorts of trouble and complication of your configuration. - Register all Web API Controllers explicitly in the container. Registering controllers explicitly will ensure that Simple Injector will throw an exception when a controller can't be resolved. Besides, this allows you to call
container.Verify()
which will make the application fail during startup when the configuration is invalid (a verifiable configuration is important). And this also allows you to diagnose the configuration which gives you even more confidence about the correctness of your configuration.
My advice is to place MVC and Web API in their own project. This will make things much easier.
Registering all Web API controllers can be done with the following code:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
UPDATE:
Because this error is so common, newer versions of the SimpleInjectorWebApiDependencyResolver
class will simply never return null
when a controller type is requested. Instead it will throw a descriptive error. Because of this you should never see error anymore, as long as you use the official SimpleInjectorWebApiDependencyResolver
.
Following setups work for me:
1) include Unity.WebAPI from https://www.nuget.org/packages/Unity.WebAPI/ 2) in UnityConfig
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// **** Important note -----
// register all your components with the container here
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
3) in Global.asax file
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Getting started with Unity.WebAPI
To get started, just add a call to UnityConfig.RegisterComponents() in the Application_Start method of Global.asax.cs and the Web API framework will then use the Unity.WebAPI DependencyResolver to resolve your components.
e.g.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents(); // <----- Add this line
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Add your Unity registrations in the RegisterComponents method of the UnityConfig class. All components that implement IDisposable should be registered with the HierarchicalLifetimeManager to ensure that they are properly disposed at the end of the request.