We have an ASP.NET MVC 4 based application that's a couple of years old, and I'm working on ridding it of some technical debt. One of the things I'm doing is introduce dependency injection, so that we can better separate the business logic from the data access implementation, and make it less painful to write isolated unit tests. I've gone with Simple Injector, but I'm having some issues.
I've followed the MVC integration guide in the Simple Injector documentation. It describes the initialization process like this:
- Create a container
- Register types in the container
- Verify the container (optional)
- Override the default dependency resolver
So, here's the way this is implemented in the application so far. I've removed logging statements for clarity, and added marker comments for the steps above:
// 1
var container = new Container();
var webRequestLifestyle = new WebRequestLifestyle();
// 2
container.Register<IOrganizationService>(
delegate
{
var proxy = new OrganizationServiceProxy(
organizationServiceManagement, clientCredentials);
proxy.EnableProxyTypes();
return proxy;
},
webRequestLifestyle);
container.RegisterSingle<ILoggerProvider>(LoggerProvider); // static field
container.Register<IExternalLinkRepository, ExternalLinkRepository>(webRequestLifestyle);
container.Register<IQueueRepository, QueueRepository>(webRequestLifestyle);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
// 3
container.Verify(VerificationOption.VerifyAndDiagnose);
// 4
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
The above code fails on step 3 when attempting to instantiate the MVC controllers, throwing System.InvalidOperationException: An error occurred when trying to create a controller of type 'MyProject.MyNamespace.MyController'. Make sure that the controller has a parameterless public constructor.
Which makes sense, because my controllers are set up for constructor injection. For example:
public MyController(ILoggerProvider loggerProvider)
{
Logger = loggerProvider.Get(GetType());
}
The default MVC controller activator wouldn't know what to do with this. However, what I don't understand is why the Container.Verify
method of Simple Injector hits the default controller activator of MVC at all. Shouldn't the container innately use Simple Injector's dependency resolution to test the dependency graph? Looking through the exception call stack, it originates at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create
, so it definitely goes outside the bounds of Simple Injector at some point.
However, when I swap the order of steps 3 and 4:
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
container.Verify(VerificationOption.VerifyAndDiagnose);
It successfully verifies the container, and dependency injection works as expected in the application as well. This seems to fix the problems for now. Still, I'm wondering:
- Why does Simple Injector use MVC's default controller activator to test dependency resolution? Is this expected/documented anywhere?
- Are there any side effects to setting the custom resolver first, then verifying? I'm asking because this is contrary to the guide found in the documentation. It seems to work as expected, and if either of them fail the application will crash anyway, so from the application's point of view it doesn't seem to matter.