2011-11-20 20 views
8

Por el momento, tengo un ControllerFactory personalizado en el que me inyecto mi contenedor Unidad:con Unity para inyectar dependencias en una costumbre ActionFilter

en Application_Start Global.asax():

var container = InitContainer(); 
DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 

var factory = new UnityControllerFactory(container); 
ControllerBuilder.Current.SetControllerFactory(factory); 

En el fábrica de controlador de E puso mis controladores de utilizar una ActionInvoker encargo de este modo:

protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 
{ 
    var controller = base.GetControllerInstance(requestContext, controllerType) as Controller; 

    if (controller != null) 
     controller.ActionInvoker = new UnityActionInvoker(_container); 

    return controller; 
} 

último en mi ActionInvoker personalizada, trato de acciones que se invocan utilizando acumulación de la ActionInvokers contenedor:

protected override ActionExecutedContext InvokeActionMethodWithFilters(
     ControllerContext controllerContext, 
     IList<IActionFilter> filters, 
     ActionDescriptor actionDescriptor, 
     IDictionary<string, object> parameters) 
{ 
    var builtUpFilters = new List<IActionFilter>(); 

    foreach (IActionFilter actionFilter in filters) 
    { 
     builtUpFilters.Add(_container.BuildUp<IActionFilter>(actionFilter)); 
    } 

    return base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters); 
} 

Este es un ejemplo de uno de los ActionFilters que se está construyendo:

public class PopulatRolesAttribute : ActionFilterAttribute, IActionFilter 
{ 
    private const string RolesKey = "roles"; 

    [Dependency] 
    public Func<IMetadataService> Service { get; set; } 

    public PopulatRolesAttribute() 
    { 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (filterContext.Controller.ViewData[RolesKey] == null) 
     { 
      filterContext.Controller.ViewData[RolesKey] = Service().GetRoles(); 
     } 
    } 
} 

El problema es que la propiedad pública sobre mi costumbre ActionFilterAttribute Nunca se inyecta con cualquier cosa, ¡permanece nulo en la ejecución! No puedo ver por qué mi filtro no está siendo creado correctamente por el contenedor. El tipo que se inyecta se ha registrado correctamente, así:

container.RegisterInstance(new ChannelFactory<IMetadataService>(
    new BasicHttpBinding(), 
    new EndpointAddress("http://example.com/ABSApplication/MetadataService.svc"))); 

container.RegisterInstance<Func<IMetadataService>>(
    () => container.Resolve<ChannelFactory<IMetadataService>>().CreateChannel()); 

Y también se está inyectando en otra parte de la aplicación (aunque no a través de .Buildup). Este es prácticamente el mismo proceso seguido por este blog post. ¿Qué pieza del rompecabezas me estoy perdiendo?

+0

Por curiosidad, ¿por qué no hacer esto en, por ejemplo, autenticar la solicitud, petición PREAUTH, etc y la memoria caché ellos (la sesión, etc.) por lo que hay para cada solicitud, mientras que el usuario está conectado? –

+0

Mi intención original era encapsular esta funcionalidad para poder agregarla cada vez que una acción lo requiriera. Si después de la revisión usaría los datos recuperados por los filtros en una cantidad significativa, ciertamente los almacenaría en caché globalmente para su reutilización a lo largo de la aplicación. En realidad, está empezando a parecer que sería una solución más fácil de todos modos, independientemente de la reutilización. Todavía tengo curiosidad por saber por qué 'container.BuildUp' no funciona. –

+0

Encontré esta muestra, voy a verla en breve. La fuente también está disponible para su descarga allí http://msdn.microsoft.com/en-us/gg618494 –

Respuesta

8

Haría esto de forma ligeramente diferente. Yo:

  1. instalar el paquete Nuget unity.mvc3

  2. llamada la bootstrapped.initialise() como se menciona en el documento txt el paquete se suma al proyecto

  3. definir su asignación IMetadataService en el inicializar a su tipo de hormigón

  4. complemento IMetadataService a su constructor

La diferencia entre su implementación y el artículo al que hace referencia es que usa Func, que no estoy seguro si eso agrega un problema diferente a la mezcla aquí. Tengo que imaginar que funciona como el método anterior (sin Func) funciona bien para mí.

Editar: Código de Brad Wilson trabajó bien para mí aquí: http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html

partes aplicables (por favor ver el siguiente enlace)

Global.asax.cs

 

protected void Application_Start() { 
    // ... 

    var oldProvider = FilterProviders.Providers.Single(
     f => f is FilterAttributeFilterProvider 
    ); 
    FilterProviders.Providers.Remove(oldProvider); 

    var container = new UnityContainer(); 
    var provider = new UnityFilterAttributeFilterProvider(container); 
    FilterProviders.Providers.Add(provider); 

    // ... 
} 
 

El filtro sí mismo:

 

using System; 
using System.Web.Mvc; 
using Microsoft.Practices.Unity; 

public class InjectedFilterAttribute : ActionFilterAttribute { 

    [Dependency] 
    public IMathService MathService { get; set; } 

    public override void OnResultExecuted(ResultExecutedContext filterContext) { 
     filterContext.HttpContext.Response.Write(
      String.Format("

The filter says 2 + 3 is {0}.

", MathService.Add(2, 3)) ); } }

y UnityFilterAttributeFilterProvider.cs

 

using System.Collections.Generic; 
using System.Web.Mvc; 
using Microsoft.Practices.Unity; 

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider { 
    private IUnityContainer _container; 

    public UnityFilterAttributeFilterProvider(IUnityContainer container) { 
     _container = container; 
    } 

    protected override IEnumerable GetControllerAttributes(
       ControllerContext controllerContext, 
       ActionDescriptor actionDescriptor) { 

     var attributes = base.GetControllerAttributes(controllerContext, 
                 actionDescriptor); 
     foreach (var attribute in attributes) { 
      _container.BuildUp(attribute.GetType(), attribute); 
     } 

     return attributes; 
    } 

    protected override IEnumerable GetActionAttributes(
       ControllerContext controllerContext, 
       ActionDescriptor actionDescriptor) { 

     var attributes = base.GetActionAttributes(controllerContext, 
                actionDescriptor); 
     foreach (var attribute in attributes) { 
      _container.BuildUp(attribute.GetType(), attribute); 
     } 

     return attributes; 
    } 
} 
 
+1

Aprecio la dirección del paquete Unity.Mvc3: encapsula la resolución de dependencia para Mvc3 usando Unity muy bien. Sin embargo, no creo que resuelva mi problema. Si tengo un método en un controlador decorado con un filtro como el siguiente: '[PopulatRoles] public ActionResult Add() {' ​​¿cómo puedo lograr la inyección en PopulateRoles ActionFilterAttribute? No puedo usar la inyección de constructor ya que es un atributo y no puedo utilizar su constructor. Por lo tanto, necesito construir el atributo a medida que se crea. –

+0

Como apéndice, he visto que ninject hace algo completamente diferente como este [enlace] (http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for- mvc3 /) para permitir la inyección de constructores en los filtros, sin embargo, no estoy seguro si esto se puede lograr con Unity. –

+0

Los filtros se resuelven internamente en MVC. Tendré que hacer una prueba rápida aquí. –

Cuestiones relacionadas