How to configure dependency injection using ASP.NET MVC 3 RTM

I am upgrading a web application from ASP.NET 3 Preview 1 to RTM, and I am confused by the updated approach to dependency injection. I use StructureMap for this, but this is not very relevant for my question. First of all, I needed to do the following:

x.For<IControllerFactory>().Use<DefaultControllerFactory>(); x.For<IServiceLocator>().Use(MvcServiceLocator.Current); 

Now it seems to me that I need to provide implementations of IControllerActivator, IViewPageActivator and ModelMetadataProvider, because otherwise I get an error message from StructureMap because MVC is trying to find them using the dependency resolver. From a look at the source of MVC, there seems to be no default implementations. Am I missing something in the setup? Of course, they should be configured by agreement?

Examples of what you need to configure and how using StructureMap will be evaluated. For reference, I'm currently using the following ugly kludge, which forces MVC to use their 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 implementation of StructureMap for Dependency Resolver - the problem is why MVC complains that all of these interfaces are not configured in the container.

+4
source share
3 answers

I realized this thanks to the @Michael Carman link posted in a comment on his answer. I am not sure about this etiquette as to whether he justifies his actual answer, since it was not entirely correct (I gave him a +1 vote), but I thought I would send my own answer to explain the release was.

The problem was the combination of my implementation of IDependencyResolver and my container configuration. I initially had:

 public class StructureMapDependencyResolver : IDependencyResolver { public object GetService(Type serviceType) { return ObjectFactory.GetInstance(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { foreach (object obj in ObjectFactory.GetAllInstances(serviceType)) { yield return obj; } } } 

but now I changed it based on Steve Smith's blog post related to Jeremy Miller's Post :

 public class StructureMapDependencyResolver : IDependencyResolver { public object GetService(Type serviceType) { if (serviceType.IsAbstract || serviceType.IsInterface) { return ObjectFactory.TryGetInstance(serviceType); } else { return ObjectFactory.GetInstance(serviceType); } } public IEnumerable<object> GetServices(Type serviceType) { foreach (object obj in ObjectFactory.GetAllInstances(serviceType)) { yield return obj; } } } 

This alone does not solve the problem until I remove this configuration expression:

 x.For<IControllerFactory>().Use<DefaultControllerFactory>(); 

According to the documentation, TryGetInstance returns the types registered in the container and returns null if none exist. I assume MVC 3 code relies on this behavior to indicate that it should use its default values, so in my original case I had to register these default values ​​with my container. Difficult!

+4
source

I managed to get StructureMap to work with ASP.NET MVC3 by creating the Dependency Resolver (IDependencyResolver) class and then registering this class in global.asax. I have not fully tested this code. But it worked without any problems in two applications.

StructureMapDependencyResolver.cs

 using System.Linq; using System.Web.Mvc; using StructureMap; namespace SomeNameSpace { public class StructureMapDependencyResolver : IDependencyResolver { private readonly IContainer container; public StructureMapDependencyResolver(IContainer container) { this.container = container; } public object GetService(System.Type serviceType) { try { return this.container.GetInstance(serviceType); } catch { return null; } } public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType) { return this.container.GetAllInstances<object>() .Where(s => s.GetType() == serviceType); } } } 

Global.asax.cs

  public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); DependencyResolver.SetResolver(new StructureMapDependencyResolver(InitContainer())); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } private static IContainer InitContainer() { ObjectFactory.Initialize(x => { x.Scan(y => { y.WithDefaultConventions(); y.AssembliesFromApplicationBaseDirectory(); y.LookForRegistries(); }); }); return ObjectFactory.Container; } 
+8
source

This works for me for both MVC and Web API.

 namespace Web.Utilities.DependencyResolvers { public class StructureMapResolver : IServiceLocator, IDependencyResolver { private readonly IContainer _container; public StructureMapResolver(IContainer container) { if (container == null) throw new ArgumentNullException("container"); this._container = container; } public IDependencyScope BeginScope() { return new StructureMapResolver(this._container.GetNestedContainer()); } public object GetInstance(Type serviceType, string instanceKey) { if (string.IsNullOrEmpty(instanceKey)) { return GetInstance(serviceType); } return this._container.GetInstance(serviceType, instanceKey); } public T GetInstance<T>() { return this._container.GetInstance<T>(); } public object GetService(Type serviceType) { return GetInstance(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return this._container.GetAllInstances(serviceType).Cast<object>(); } public T GetInstance<T>(string instanceKey) { return this._container.GetInstance<T>(instanceKey); } public object GetInstance(Type serviceType) { return serviceType.IsAbstract || serviceType.IsInterface ? this._container.TryGetInstance(serviceType) : this._container.GetInstance(serviceType); } public IEnumerable<T> GetAllInstances<T>() { return this._container.GetAllInstances<T>(); } public IEnumerable<object> GetAllInstances(Type serviceType) { return this._container.GetAllInstances(serviceType).Cast<object>(); } public void Dispose() { this._container.Dispose(); } } } 
0
source

Source: https://habr.com/ru/post/1335742/


All Articles