unity tutorial net mvc injection dependency container asp c# .net asp.net-web-api unity-container

c# - tutorial - web api 2 unity



No se pueden inyectar dependencias en el controlador de API web ASP.NET utilizando Unity (11)

¿Alguien ha tenido éxito al usar un contenedor IoC para inyectar dependencias en los controladores WebAPI de ASP.NET? Parece que no puedo hacer que funcione.

Esto es lo que estoy haciendo ahora.

En mi global.ascx.cs :

public static void RegisterRoutes(RouteCollection routes) { // code intentionally omitted } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); IUnityContainer container = BuildUnityContainer(); System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver( t => { try { return container.Resolve(t); } catch (ResolutionFailedException) { return null; } }, t => { try { return container.ResolveAll(t); } catch (ResolutionFailedException) { return new System.Collections.Generic.List<object>(); } }); System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); BundleTable.Bundles.RegisterTemplateBundles(); } private static IUnityContainer BuildUnityContainer() { var container = new UnityContainer().LoadConfiguration(); return container; }

Mi fábrica de controladores:

public class UnityControllerFactory : DefaultControllerFactory { private IUnityContainer _container; public UnityControllerFactory(IUnityContainer container) { _container = container; } public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) { Type controllerType = base.GetControllerType(requestContext, controllerName); return (IController)_container.Resolve(controllerType); } }

Parece que nunca se ve en mi archivo unit para resolver dependencias, y me sale un error como:

Se produjo un error al intentar crear un controlador de tipo ''PersonalShopper.Services.WebApi.Controllers.ShoppingListController''. Asegúrese de que el controlador tenga un constructor público sin parámetros.

en System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpControllerContext controllerContext, Type controllerType) en System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance (HttpControllerContext controllerContext, HttpControllerDescriptor controllerDescriptor) en System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController (HttpControllerContext controllerContext, String controllerName) en System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal (solicitud HttpRequestMessage, CancellationToken cancellationToken) en System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync (solicitud HttpRequestMessage, CancellationToken cancellationToken)

Controlador se ve así:

public class ShoppingListController : System.Web.Http.ApiController { private Repositories.IProductListRepository _ProductListRepository; public ShoppingListController(Repositories.IUserRepository userRepository, Repositories.IProductListRepository productListRepository) { _ProductListRepository = productListRepository; } }

Mi archivo de unidad se ve así:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <container> <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" /> </container> </unity>

Tenga en cuenta que no tengo un registro para el controlador en sí porque en las versiones anteriores de mvc, la fábrica del controlador se daría cuenta de que las dependencias debían resolverse.

Parece que nunca se está llamando a mi fábrica de controladores.


Breve resumen para ASP.NET Web API 2.

Instalar Unity desde NuGet.

Crea una nueva clase llamada UnityResolver :

using Microsoft.Practices.Unity; using System; using System.Collections.Generic; using System.Web.Http.Dependencies; public class UnityResolver : IDependencyResolver { protected IUnityContainer container; public UnityResolver(IUnityContainer container) { if (container == null) { throw new ArgumentNullException("container"); } this.container = container; } public object GetService(Type serviceType) { try { return container.Resolve(serviceType); } catch (ResolutionFailedException) { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return container.ResolveAll(serviceType); } catch (ResolutionFailedException) { return new List<object>(); } } public IDependencyScope BeginScope() { var child = container.CreateChildContainer(); return new UnityResolver(child); } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { container.Dispose(); } }

Crea una nueva clase llamada UnityConfig :

public static class UnityConfig { public static void ConfigureUnity(HttpConfiguration config) { var container = new UnityContainer(); container.RegisterType<ISomethingRepository, SomethingRepository>(); config.DependencyResolver = new UnityResolver(container); } }

Editar App_Start -> WebApiConfig.cs

public static void Register(HttpConfiguration config) { UnityConfig.ConfigureUnity(config); ...

Ahora funcionará.

Fuente original pero un poco modificada: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection


Después de leer las respuestas, todavía tuve que investigar mucho para encontrar esta oportunidad, así que aquí es para beneficio de los compañeros: esto es todo lo que necesitas hacer en ASP.NET 4 Web API RC (como el 8 de agosto) ''13):

  1. Agregue una referencia a "Microsoft.Practices.Unity.dll" [Estoy en la versión 3.0.0.0, agregada a través de NuGet]
  2. Agregue una referencia a "Unity.WebApi.dll" [Estoy en la versión 0.10.0.0, agregada a través de NuGet]
  3. Registre sus asignaciones de tipos con el contenedor, similar al código en Bootstrapper.cs que se agrega a su proyecto mediante el proyecto Unity.WebApi.
  4. En los controladores que heredan de la clase ApiController, cree constructores parametrizados que tengan sus tipos de parámetros como los tipos mapeados

Y he aquí, ¡obtienes las dependencias inyectadas en tu constructor sin otra línea de código!

NOTA: obtuve esta información de uno de los comentarios en THIS blog por su autor.


En un RC reciente, descubro que ya no hay un método SetResolver. Para habilitar tanto el IoC para el controlador como el webapi, uso Unity.WebApi (NuGet) y el siguiente código:

public static class Bootstrapper { public static void Initialise() { var container = BuildUnityContainer(); GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator())); } private static IUnityContainer BuildUnityContainer() { var container = new UnityContainer(); container.Configure(c => c.Scan(scan => { scan.AssembliesInBaseDirectory(); scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes(); })); return container; } } public class ControllerActivator : IControllerActivator { IController IControllerActivator.Create(RequestContext requestContext, Type controllerType) { return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController; } }

También uso UnityConfiguration (también de NuGet) para la magia IoC. ;)



Este problema ocurre debido al registro de controladores con Unity. Lo resolví usando el registro por convención como se muestra a continuación. Por favor, filtra cualquier tipo adicional según sea necesario.

IUnityContainer container = new UnityContainer(); // Do not register ApiControllers with Unity. List<Type> typesOtherThanApiControllers = AllClasses.FromLoadedAssemblies() .Where(type => (null != type.BaseType) && (type.BaseType != typeof (ApiController))).ToList(); container.RegisterTypes( typesOtherThanApiControllers, WithMappings.FromMatchingInterface, WithName.Default, WithLifetime.ContainerControlled);

Además, el ejemplo anterior usa AllClasses.FromLoadedAssemblies() . Si está mirando cargar ensamblajes desde la ruta base, es posible que no funcione como se esperaba en un proyecto de API web utilizando Unity. Por favor, eche un vistazo a mi respuesta a otra pregunta relacionada con esto. https://.com/a/26624602/1350747



Lo averigué.

Para ApiControllers , MVC 4 usa un System.Web.Http.Dispatcher.IHttpControllerFactory y System.Web.Http.Dispatcher.IHttpControllerActivator para crear los controladores. Si no hay un método estático para registrar cuál es la implementación de estos, son; cuando se resuelven, el marco mvc busca las implementaciones en el resolutor de dependencias, y si no se encuentran, usa las implementaciones predeterminadas.

Obtuve la resolución unitaria de las dependencias del controlador trabajando haciendo lo siguiente:

Creado un UnityHttpControllerActivator:

public class UnityHttpControllerActivator : IHttpControllerActivator { private IUnityContainer _container; public UnityHttpControllerActivator(IUnityContainer container) { _container = container; } public IHttpController Create(HttpControllerContext controllerContext, Type controllerType) { return (IHttpController)_container.Resolve(controllerType); } }

Registrado ese activador de controlador como la implementación en el contenedor de unidad en sí:

protected void Application_Start() { // code intentionally omitted IUnityContainer container = BuildUnityContainer(); container.RegisterInstance<IHttpControllerActivator>(new UnityHttpControllerActivator(container)); ServiceResolver.SetResolver(t => { // rest of code is the same as in question above, and is omitted. }); }


Microsoft ha creado un paquete para esto.

Ejecute el siguiente comando desde la consola del administrador de paquetes.

paquete de instalación Unity.AspNet.WebApi

Si ya tiene Unity instalado, le preguntará si desea sobrescribir App_Start / UnityConfig.cs. Responda no y continúe.

No es necesario cambiar ningún otro código y DI (con unidad) funcionará.


Tuve el mismo error y buscaba soluciones en internet en un par de horas. Finalmente, parecía que tenía que registrar Unity ANTES de llamar al WebApiConfig.Register. Mi global.asax ahora se ve como

public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { UnityConfig.RegisterComponents(); AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } }

Para mí, esto resolvió el problema de que Unity no podía resolver las dependencias en mis controladores


Tuve el mismo problema al usar el paquete Unity.WebAPI NuGet. El problema fue que el paquete nunca agregó una llamada a UnityConfig.RegisterComponents() en mi Global.asax.

Global.asax.cs debería verse así:

public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { UnityConfig.RegisterComponents(); ... } }


Tuve la misma excepción lanzada, y en mi caso tuve un conflicto entre los binarios MVC3 y MVC4. Esto impedía que mis controladores se registraran correctamente con mi contenedor IOC. Verifique su web.config y asegúrese de que apunta a las versiones correctas de MVC.