2010-11-12 7 views
13

Tengo una clase de atributo personalizada derivada de AuthorizationAttribute, que realiza seguridad personalizada en las acciones del controlador. El método OnAuthorizationCore depende de varios otros componentes (por ejemplo, DAL) para determinar si un usuario puede invocar una acción.Cómo resuelvo la Inyección de dependencia en los atributos del filtro MVC

Estoy usando Autofac para inyección de dependencia. ExtensibleActionInvoker afirma ser capaz de realizar inyecciones de propiedad en filtros de acción. Establecer las propiedades de un atributo en el tiempo de ejecución (lo cual parece una mala idea) funcionará en una simple prueba de unidad, pero en un servidor web ocupado y de subprocesos múltiples es inevitable que salga mal, por lo que esta idea parece un antipatrón. De ahí esta pregunta:

Si mi AuthorizationAttribute depende de otros componentes para funcionar correctamente, ¿cuál es el patrón de [arquitectura] correcto para lograr esto?

es decir, AuthorizationAttribute depende de IUserRepository ... cómo debería resolver esta relación?

Respuesta

17

ExtensibleActionInvoker afirma ser capaz de realizar inyecciones de propiedad en filtros de acción.

Corrija, pero no confunda los filtros de acción con los atributos que podrían no implementarlos. La forma más limpia de abordar esto en ASP.NET MVC divide las responsabilidades, aunque el marco MVC le permite combinarlas.

ejemplo, el uso de un par de clases - una clase de atributo que contiene datos solamente:

// Just a regular old attribute with data values 
class SomeAttribute : Attribute { ... } 

y un filtro que tiene dependencias inyectada:

// Gets dependencies injected 
class SomeFilter : IActionFilter { ... } 

SomeFilter simplemente utiliza el enfoque típico de conseguir el atributo SomeAttribute del controlador o método de acción a través del GetCustomAttributes() para hacer cualquier trabajo que sea necesario.

continuación, puede utilizar ExtensibleActionInvoker a cablear el filtro:

builder.RegisterControllers(...).InjectActionInvoker(); 
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>(); 
builder.RegisterType<SomeFilter>().As<IActionFilter>(); 

Podría ser un poco más código que le iba a escribir usando el enfoque de atributos como filtro, pero la calidad del código ser mejor a largo plazo (por ejemplo, evitando las limitaciones de los atributos y la incomodidad de las soluciones de Localizador de servicios).

+0

Gracias Nick, ¡tanto por una respuesta exhaustiva como por un marco brillante! – Mark

2

No hay una forma directa de hacerlo antes del MVC2. Hay una técnica interesante detallada aquí: http://www.mattlong.com.au/?p=154. Sugeriría usar el Common Service Locator para abstraer esto y ubicar su contenedor DI.

Si está utilizando MVC 3, puede utilizar MVC Service Location

+2

¿De qué sirve usar CSL si es un localizador de servicios de todos modos? CSL generalmente se usa cuando sabe que su código va a ser reutilizado por otra persona que pueda preferir otro contenedor. No piense que hay otro razonamiento para abstraerlo. –

+0

Aquello se ha discutido hasta la muerte; siempre se reduce a un punto de vista ideológico, –

2

Me parece que la mejor manera de lograr esto es hacer de tripas corazón y aceptar una dependencia de autofac sí. Si bien la dependencia del IoC es en sí misma un antipatrón, es algo más paliable. Puede implementar una propiedad de la siguiente manera:

public class UserAuthorizeAttribute : AuthorizeAttribute 
{    
    public IUserRepository CurrentUserService 
    { 
     get 
     { 
      var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance; 
      var cp = cpa.ContainerProvider; 
      return cp.RequestLifetime.Resolve<IUserRepository>(); 
     } 
    } 
} 
    ... 
0

La inyección del constructor parece ser imposible sin cambiar la forma de registro del filtro.

Incluso in Asp.Net Mvc3:

Un lugar donde la inyección de dependencia ha sido difícil en el pasado es el interior del filtro mismos atributos. Como el tiempo de ejecución de .NET framework es realmente responsable de crear estas instancias de atributo, no podemos usar una estrategia de inyección de dependencia tradicional.

Entonces, lo mejor es la propiedad de inyección (Mvc3 proporciona algo de soporte para la caja).

Aquí hay un how to para hacerlo manualmente.

Yo personalmente uso MvcExtensions. Estoy bien con registrarlos en different way. Aquí está usage.

Otra cosa que quizás quiera investigar es el proyecto MvcTurbine. A diferencia del proyecto MvcExtensions, que es más general, MvcTurbine es principalmente para proporcionar soporte de inyección de dependencias.

Cuestiones relacionadas