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
.
SimpleInjector: Injection does not work with MVC 4 ASP.NET Web API
From the stack trace I can see that you are using the new .NET 4.5 ASP.NET Web API and Simple Injector is not in the presented call graph. This probably means that you haven't configured the Simple Injector for use with the new Web API, which is a different registration than what you need for MVC (for some strange reason, and I sincerely hope they fix this in the final release). Since you didn't register a Simple Injector specific System.Web.Http.Dependencies.IDependencyResolver
implementation to the Web API's GlobalConfiguration.Configuration.DependencyResolver
, you'll get the default behavior, which will only work with default constructors.
Take a look at this Stackoverflow answer Does Simple Injector supports MVC 4 ASP.NET Web API? to see how to configure Simple Injector with the new ASP.NET Web API.
UPDATE
Note that you can get this exception even if you configured the DependencyResolver
correctly, but when you didn't register register your Web API Controllers explicitly. This is caused by the way Web API is designed.
Always register your Controllers explicitly.
Parameter not registered when using Simple Injector to inject into an web api Controller Constructor
I never used Simple Injector before, but the IoC patterns is always the same. So as Steven says, you should register IChurchService
in the container, so the Framework knows whats the Instance type to inject when demanded.
private static void InitializeContainer(Container container)
{
// For instance:
container.Register(typeof(IRepository<>), typeof(EFRepository<>));
//Adding this should resolve it
container.Register(typeof(IChurchService), typeof(ChurchService));
}
If ChurchService
has any dependencies make sure to register those as well. Register all dependencies needed to complete the object graph
Resolve dependencies in ASP.NET Web API with Simple Injector and IHttpControllerActivator
Yes, your implementation is valid.
Only be careful not to use both the SimpleInjectorWebApiDependencyResolver
and the SimpleInjectorControllerActivator
in the same application. Both start an ExecutionContextScope
which could lead to having two scopes within the same web request, so they are mutually exclusive.
A general advantage of using a controller activator over the dependency resolver is that the dependency resolver contract forces the adapter to return null
when a service can't be created. This is a very common problem that developers run into, and it often causes the confusing controller does not have a default constructor exception. This problem does not exist when using an IHttpControllerActivator
, since the contract forces you to return a value or throw an exception.
The Simple Injector Web API integration project however, prevents this problem with dependency resolver, by never returning null
(but throwing an exception instead) in case the requested service is an API controller (and thereby implicitly breaking the IDependencyResolver
's contract).
An advantage of using the SimpleInjectorDependencyResolver
is that it becomes easier to create message handlers that operate within the execution context scope, since you can trigger the creation of this scope by calling request.GetDependencyScope()
method. With the current implementation, the scope just gets started at the time that the controller gets created, which is after you run the handlers. Changing this isn't that hard, but involves changing your controller activator and have an outermost handler that starts the execution context scope (or again falling back on a dependency resolver that manages the execution context scope).
One of the arguments of Mark Seemann is that it becomes hard to pass context around, which is a very valid point, as long as your components don't require this context during construction. But this is not a problem you'll experience when using Simple Injector, because there is an extension method that helps you with accessing the HttpRequestMessage
. So although the IDependencyResolver
abstraction isn't designed for getting the contextual information, there are ways to get this contextual information.
In the past we decided to go with an adapter for the IDependencyResolver
, mainly because this was the common practice with all DI containers. I partly regret this decision, but using the SimpleInjectorDependencyResolver
is now usually the easiest way of plugging in Simple Injector into Web API. We considered adding a SimpleInjectorControllerActivator
as well, but this had no practical benefit for most users, while we still would had to document when to use what. So we decided to stick with the dependency resolver adapter; an adapter for the activator is easily created for anyone who needs it, as you can see.
For ASP.NET Core however, we went into a different direction, and as you can see in the documentation, the integration package actually contains a SimpleInjectorControllerActivator
out of the box. In ASP.NET Core, the controller activator is the perfect interception point and due to the OWIN-like pipeline, a scope can be easily wrapped around a request. So with ASP.NET Core, the advised practice is to use the controller activator as interception point.
Using Simple Injector in Web API and OWIN
I had the same issue but with UnityDependencyResolver. But I think it should also work for SimpleInjectorWebApiDependencyResolver. Try to register your resolver like this (as a Property of HttpConfiguration):
public void Configuration(IAppBuilder app)
{
var container = GetContainer(); // Initialise container
HttpConfiguration config = new HttpConfiguration
{
DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
};
WebApiConfig.Register(config);
app.UseWebApi(config);
}
Simple Injector with multiple WebAPI projects
RegisterWebApiControllers
uses reflection under the covers to search for implementations of ApiController
.
I guess, based upon the error you get, project B is referenced by project A and the call to container.RegisterWebApiControllers
in project A finds and registers the controllers of project B also.
Now when .Verify()
is called it will scan the constructors of the ApiControllers
in project B, finds a dependency on IUserService
and breaks because this registration is actually missing in project A.
The integration package contains another overload for RegisterWebApiControllers
which takes an array of assemblies that must be scanned for ApiControllers
instead of scanning through all referenced assemblies.
Assuming the assembly of project A contains all ApiControllers
that need to be registered this overload can be used in project A like:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration,
new[] {typeof(MyApiControllerInProjectA).Assembly});
Related Topics
Best Way to Tackle Global Hotkey Processing in C#
How to Get the "Friendly" Os Version Name
How to Sort a Two-Dimensional (Rectangular) Array in C#
C# Covariant Return Types Utilizing Generics
How to Detect Keypress While Not Focused
How to Avoid System.Io.Pathtoolongexception
How to Use .Net Reflection to Check for Nullable Reference Type
How to De-Elevate Privileges for a Child Process
How to Use Enumwindows to Find Windows with a Specific Caption/Title
Drag and Drop to Desktop/Explorer
How to Add a .Dll Reference to a Project in Visual Studio
Page.Datacontext Not Inherited from Parent Frame
Pair-Wise Iteration in C# or Sliding Window Enumerator
Why Is the Iteration Variable in a C# Foreach Statement Read-Only
5.7.57 Smtp - Client Was Not Authenticated to Send Anonymous Mail During Mail from Error
What Is an Algorithm to Diff the Two Strings in the Same Way That So Does on the Version Page