asp.net mvc - injection - Inyectar dependencias en el atributo de filtro de acción de API web personalizado con Autofac
dependency injection asp net core (4)
Estoy tratando de resolver las dependencias de mi AuthorizeAttribute
personalizado que utilizo para decorar mis controladores API en una aplicación MVC4. El problema es que continúo obteniendo una NullReferenceException
en la dependencia de servicio que uso dentro de mi filtro personalizado. Aquí está mi configuración de Autofac:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly)
.Where(t => t.Name.EndsWith("Mapper"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly)
.Where(t => t.Name.EndsWith("Svc"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
}
}
y mi filtro de autorización personalizado:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc _authenticationSvc;
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!base.IsAuthorized(actionContext))
{
return false;
}
var trueUserId = WebSecurity.CurrentUserId;
if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true;
// NullReferenceException on _authenticationSvc
}
}
Según los documentos oficiales, todo lo que se necesita es:
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
Pero eso tampoco parece hacer el truco. Aprecio cualquier ayuda.
Además de configurar la inyección de propiedades, como se describe en otras respuestas, también puede resolver explícitamente las dependencias en la OnActivating
llamada OnActivating
.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private IAuthenticationSvc _authenticationSvc;
public void SetAuthenticationSvc(IAuthenticationSvc svc)
{
this._authenticationSvc = svc;
}
}
Y luego registre el tipo:
builder.RegisterType<MyAuthorizeAttribute>()
.OnActivating(_ => _.Instance.SetAuthenticationSvc(_.Context.Resolve<IAuthenticationSvc>()));
Nota: Puedes hacer lo mismo con una propiedad en lugar de un método. Elegí usar un método aquí solo para ilustrar que esta solución no dependía de PropertiesAutowired
.
Además de la respuesta de @Toan Nguyen, si tienes esto ...
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
... parece que también necesita (o puede necesitar) la primera línea a continuación:
builder.RegisterFilterProvider();
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
Referencia: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html
Creo que la documentación de Autofac ofrece una solución mucho más sencilla para los filtros de acción de WebApi.
public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the request lifetime scope so you can resolve services.
var requestScope = actionContext.Request.GetDependencyScope();
// Resolve the service you want to use.
var service = requestScope.GetService(typeof(IMyService)) as IMyService;
// Do the rest of the work in the filter.
service.DoWork();
}
}
No es "DI puro", ya que utiliza el localizador de servicios, pero es simple y funciona con el alcance de la solicitud. No necesita preocuparse por registrar un filtro de acción específico para cada controlador WebApi.
Debe configurar la inyección de propiedad para su atributo.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
y el constructor
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();