2011-04-06 13 views
10

Tengo una clase de autorización personalizada que hereda de FilterAttribute y implementa IAuthorizationFilter. Estoy usando la última versión del soporte Ninject w/asp.net MVC 3.Autorización personalizada MVC 3 y Ninject IoC

El problema que tengo es que estoy usando la inyección de constructor para inyectar un repositorio. Pero cuando se llama OnAuthorization, el repositorio es nulo. Aquí está el código ...

public class MyAuthorizeAttribute : FilterAttribute, IAuthorizationFilter 
    { 
     private readonly IMyRepo _MyRepo; 

     public MyAuthorizeAttribute() { } 
     public MyAuthorizeAttribute(IMyRepo myRepo) 
     { 
      _MyRepo= myRepo; //this gets initialized 
     } 


     public void OnAuthorization(AuthorizationContext filterContext) 
     { 
      _MyRepo.DoStuff(); //<< Null, wtf 

     } 
    } 

Filtro Encuadernación:

Bind<IMyRepo>().To<MyRepo>().InRequestScope(); 


this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Controller, null).WhenControllerHas<MyAuthorizeAttribute >(); 

Actualización: Una cosa que he notado es este filtro es a nivel del controlador. Tengo otros filtros en el ámbito de acción que parecen funcionar correctamente ... ¿podría ser esa la razón?

Actualización 2: He confirmado que si cambio el ámbito de filtro a la acción, a continuación, el repositorio está disponible OnAuthorization (no nulo).

Esto funciona a continuación, sin embargo necesito el alcance del controlador, no la acción.

this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Action, null).WhenActionMethodHas<MyAuthorizeAttribute >(); 
+0

Parece que se llama a su MyAuthorizeAttribute con el constructor predeterminado. – dexter

+0

@dexter, no pienses que ese es el caso. Puse breakpoint y ctor con repo se llama –

+0

¿Ha configurado el enlace del filtro en el módulo de Ninject. Mire el código de ejemplo en la sección "Inyección de dependencias para filtros" en http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/#more-2004 – WorldIsRound

Respuesta

9

atributos no son compatibles con la inyección de constructor, ya que son creados por el .NET Framework y no están bajo el control de Ninject. Si realmente quiere usar un FilterAttribute (que no recomiendo), tendrá que usar la inyección de propiedad.

En su lugar, continúe con lo que acaba de comenzar. Necesita un filtro que implemente IAuthorizationFilter (no derivado de FilterAttribute, simplemente elimínelo de su código anterior) y, además, un atributo ordinario para marcar los controladores/acciones.

A continuación, cambiar el enlace:

this.BindFilter<MyAuthorizeFilter>(FilterScope.Controller, 0).WhenControllerHas<MyAuthorizeAttribute>(); 

Ver: https://github.com/ninject/ninject.web.mvc/wiki/MVC3

El problema con que la implementación actual es que se comprueba una vez como atributo de filtro y una vez añadido como filtro normal. Uno para estas instancias tendrá el repo inyectado y el repositorio será nulo para el otro.

NOTA: puede derivar de un FilterAttribute existente si esto simplifica su implementación. Pero no lo use como un atributo en este caso, pero úselo como un filtro ordinario.

+0

Todo tiene sentido excepto para la parte "Nota". Solo por curiosidad, ¿por qué parece funcionar cuando cambio el alcance a acción en lugar de controlador? –

+0

Cambiar a acción cambiará si ya no tiene dos filtros en el controlador, sino uno en la acción (con una referencia de repos) y otro en el controlador (repositorio == nulo). No estoy seguro del orden de ejecución y si .NET ejecuta todos los IAuthorizationFilters o solo hasta que uno sea exitoso. El que está en el controlador todavía debe dar como resultado una excepción NullRef. Pero probablemente no se haya ejecutado. –

+0

Gracias por la respuesta y seguimiento Remo –

6

Es mejor extender la clase AuthorizeAttribute para que la autorización funcione correctamente con las solicitudes en caché. También necesitará usar Ninject.Web.Mvc

Deberá usar la inyección de propiedad Ninject para usar su repositorio. La inyección del constructor no funcionará con los atributos.

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    [Inject] 
    public IMyRepo MyRepo { get; set; } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     return base.AuthorizeCore(httpContext); 
    } 
} 
+2

gracias, esto es lo que originalmente tuve pero luego comencé a recibir algunas "" El proveedor subyacente falló en Open "excepciones de EF ... no sé si estaban relacionadas con el uso de autorizar el filtro o no, así que decidí probar la inyección de ctor y aquí Yo soy ... –

+0

Hola Rohan, para ser claro. La inyección del constructor no funcionará porque en el constructor pasamos los valores de los atributos (matriz params). También cuando dices inyección de propiedad - es el atributo [Inyectar] en la parte superior de la propiedad lo suficiente como para lograrlo con Ninject? ¿Puedes compartirlo como el enlace de Ninject? ¿Cómo se define eso? ¿Necesitas especificar el parámetro de entrada? Tengo un problema con la implementación similar. En mi atributo estoy accediendo a dbcontext a través de los servicios. My dbcontext tiene configuración InRequestScope, y esto previene que una excepción dbcontext sea eliminada. –

+0

que la excepción eliminada está sucediendo cuando toco mi lógica en el filtro. tps: //github.com/ninject/Ninject.Web.Mvc/wiki/Filters-and-Scoped pero no tiene mucho sentido para mí cómo exactamente implementarlo ..... –

0

Acabo de pensar que agregaría mi solución aquí ya que parece funcionar bien.

Se creó una clase que extiende AuthorizeAttribute y toma la interfaz del repositorio en el constructor.

Esta clase luego anula la función AuthorizeCore:

public class MyRoleAttribute : AuthorizeAttribute 
{ 
    private ICRepository repository; 

    public MyRoleAttribute(ICRepository Repo) 
    { 
     repository = Repo; 
    } 

protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     //Check if user authenticated 
     if (!httpContext.Request.IsAuthenticated) 
      return false; 

     //Can access items in the query string if needed 
     var id = (httpContext.Request.RequestContext.RouteData.Values["id"] as string) 
     ??(httpContext.Request["id"] as string); 

      //Can access repository that has been injected 
      if (repository.IsGroupCreator(.....)) 
      { 

       return true; 

      } 
      else 
      { 

       return false; 

      } 
    } 
} 

Luego de la inyección repositorio para trabajar añadí el código siguiente al archivo NinjectWebCommon.cs mvc:

kernel.BindFilter<MyRoleAttribute>(FilterScope.Action, 0).When(
(controllerContext, actionDescriptor) => actionDescriptor.ActionName == "MyAction"); 

Esto luego me permite para controlar en qué acciones necesito el atributo y ninject se encarga de la inyección del repositorio. Espero que esto ayude a alguien.

Cuestiones relacionadas