I am upgrading a web app from ASP.NET 3 Preview 1 to the RTM and I am confused by the updated approach to dependency injection. I am using StructureMap for this but that’s not really relevant to my question. Previously all I needed to do was as follows:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IServiceLocator>().Use(MvcServiceLocator.Current);
Now it seems like I need to provide implementations of IControllerActivator, IViewPageActivator and ModelMetadataProvider because otherwise I get an error from StructureMap because MVC tries to locate them using the dependency resolver. From a look at the MVC source there do not seem to be public default implementations. Am I missing something in setting these up? Surely these should be configured by convention?
Examples of what needs configuring and how with StructureMap would be appreciated. For reference I am currently using the following ugly kludge which forces MVC to use its internal defaults:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IDependencyResolver>().Use(() => DependencyResolver.Current);
x.For<IControllerActivator>().Use(() => null);
x.For<IViewPageActivator>().Use(() => null);
x.For<ModelMetadataProvider>().Use(ModelMetadataProviders.Current);
EDIT: Just to be clear I have a working StructureMap implementation of the Dependency Resolver – the issue is why MVC is complaining about all these interfaces not being configured in the container.
I’ve figured this out thanks to the link @Michael Carman posted in a comment on his answer. I’m not sure of the etiquette here as to whether that warrants accepting his actual answer as it wasn’t quite right (I’ve given him +1 vote) but I thought I’d post my own answer to explain exactly what the issue was.
The problem was down to a combination of my implementation of IDependencyResolver and my container configuration. Originally I had:
but I have now changed to this based on Steve Smith’s blog post linked to in Jeremy Miller’s blog post:
on its own this still doesn’t resolve the issue until I remove this configuration expression:
According to the documentation TryGetInstance only returns types registered with the container and will return null if none exist. I presume the MVC 3 code relies on this behaviour to indicate that it should use its defaults, hence in my original case I had to register these defaults with my container. Tricky one!