Pregunta Castle Windsor Dependency Resolver para MVC 3


Dado que la implementación de IoC / DI en MVC 3 probablemente esté en su forma final en el RC, estoy buscando una implementación actualizada de DependencyResolver, IControllerActivator y IViewPageActivator usando Caste Windsor. ¿Hay algún ejemplo que se haya actualizado para MVC 3 RC?

EDIT # 1 La implementación de un resolvedor de dependencias de Windsor es trivial, pero todavía falta algo. Contrario al ejemplo de Ninject de Jeff Putz (abajo), parece que no es tan simple como eso con Windsor. Después de configurar el resolvedor de dependencias como tal,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor lanza ComponentNotFoundException. Necesito proporcionar implementaciones para IControllerFactory e IControllerActivator. Dado que DefaultControllerFactory es consciente de DependencyResolver, esto se puede resolver de la siguiente manera:

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),

WindsorControllerActivator es trivial también. Sin embargo, esto lleva a otra ComponentNotFoundException para IViewPageActivator.

Esto me lleva a creer que me estoy perdiendo algo. No hay forma de que esto sea más complicado que implementar una fábrica de controladores y llamar a ControllerBuilder.Current.SetControllerFactory MVC 2.0-style.

EDIT # 2 Eché de menos el detalle sutil pero importante que el sistema de resolución de Dependencia necesita devolver nulo cuando no se puede encontrar un servicio. La implementación es la siguiente:

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

  public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

EDIT # 3

Respondiendo a una pregunta en los comentarios. Si encuentra que necesita su propio IControllerActivator, aquí una implementación simple para Windsor:

public class WindsorControllerActivator : IControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorControllerActivator(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController Create(RequestContext requestContext, Type controllerType)
    {
        return (IController)container.GetService(controllerType);
    }
}

}

Nuevamente, esto es NO necesario para obtener DI básica trabajando con Windsor y el resolvedor de dependencias MVC3.

EDIT # 4 Según algunas investigaciones y comentarios adicionales, parece que la implementación tradicional de una fábrica de controladores es el mejor enfoque para Windsor y MVC3. La preocupación es que la interfaz IDependencyResolver carece de un método de lanzamiento, lo que podría causar pérdidas de memoria con Windsor no eliminando sus componentes. Probablemente esto no sea un problema si todas sus dependencias se resuelven con el ciclo de vida de PerWebRequest, pero aún es mejor no arriesgarse. Aquí hay una implementación básica de una fábrica de controladores de Windsor para MVC3.

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

    public override void ReleaseController(IController controller)
    {
        container.Kernel.ReleaseComponent(controller);
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerComponentName = controllerName + "Controller";
        return container.Kernel.Resolve<IController>(controllerComponentName);
    }
}

EDIT # 5 Si está utilizando áreas MVC, la implementación anterior no funcionará para usted. Tendrá que registrar cada controlador en función de su nombre completo y anular GetControllerInstance en lugar de CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }

32
2017-11-10 03:02


origen


Respuestas:


La interfaz no ha cambiado desde la versión beta, por lo que todas las implementaciones para varios frameworks deberían funcionar. Y la verdad es que no es una interfaz tan complicada ... deberías poder rodar la tuya sin mucha molestia. Por ejemplo, hice esto para Ninject:

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

    public object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType);
    }
}

Luego, conéctalo en global.asax de la siguiente manera:

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

Recuerde, usted obtiene todo tipo de regalos gratis en ese punto, incluyendo DI para controladores, fábricas de controladores, filtros de acción y clases base de visualización.

EDITAR: Para ser claros, no estoy seguro de cuáles son tus "activadores", pero probablemente no los necesites. La interfaz IDependencyResolver maneja el reacondicionamiento de controladores y vistas automágicamente.


10
2017-11-10 04:25



La interfaz MVC3 IDependencyResolver tiene un gran problema: no hay método de lanzamiento. Esto significa que hay una posible pérdida de memoria si va a usarlo con Windsor. Ver la publicación de mi blog aquí:

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html


24
2018-02-03 17:06



MVCContrib es actualmente la fuente autorizada para la integración IoC-MVC. Actualmente, la rama MVC3 solo incluye implementaciones de fábrica de controlador e IDependencyResolver (y un par de otras cosas). Recomiendo bifurcar el repositorio e implementar los puntos de extensión faltantes (no debería ser demasiado difícil), luego enviar al equipo una solicitud de extracción.


2
2017-11-10 04:16