net mvc filters attribute asp c# asp.net-core dependency-injection .net-core

c# - mvc - net core authorization filter



Inyectar servicio en filtro de acción (6)

Estoy tratando de inyectar un servicio en mi filtro de acción pero no obtengo el servicio requerido inyectado en el constructor. Esto es lo que tengo:

public class EnsureUserLoggedIn : ActionFilterAttribute { private readonly ISessionService _sessionService; public EnsureUserLoggedIn() { // I was unable able to remove the default ctor // because of compilation error while using the // attribute in my controller } public EnsureUserLoggedIn(ISessionService sessionService) { _sessionService = sessionService; } public override void OnActionExecuting(ActionExecutingContext context) { // Problem: _sessionService is null here if (_sessionService.LoggedInUser == null) { context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; context.Result = new JsonResult("Unauthorized"); } } }

Y estoy decorando mi controlador así:

[Route("api/issues"), EnsureUserLoggedIn] public class IssueController : Controller { }

Startup.cs

services.AddScoped<ISessionService, SessionService>();


Filtros globales

Necesita implementar IFilterFactory :

public class AuthorizationFilterFactory : IFilterFactory { public bool IsReusable => false; public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) { // manually find and inject necessary dependencies. var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext)); return new AuthorizationFilter(context); } }

En la clase de Startup lugar de registrar un filtro real, registra su fábrica de filtros:

services.AddMvc(options => { options.Filters.Add(new AuthorizationFilterFactory()); });


Después de leer este artículo ASP.NET Core - Filtros MVC de ASP.NET Core en el mundo real (agosto de 2016) Lo implementé así:

En Starup.cs / ConfigureServices:

services.AddScoped<MyService>();

En MyFilterAttribute.cs:

public class MyFilterAttribute : TypeFilterAttribute { public MyFilterAttribute() : base(typeof (MyFilterAttributeImpl)) { } private class MyFilterAttributeImpl : IActionFilter { private readonly MyService _sv; public MyFilterAttributeImpl(MyService sv) { _sv = sv; } public void OnActionExecuting(ActionExecutingContext context) { _sv.MyServiceMethod1(); } public void OnActionExecuted(ActionExecutedContext context) { _sv.MyServiceMethod2(); } } }

En MyFooController.cs:

[MyFilter] public IActionResult MyAction() { }

Editar: Se pueden pasar argumentos como [MyFilter("Something")] utilizando la propiedad Argumentos de la clase TypeFilterAttribute: ¿Cómo agrego un parámetro a un filtro de acción en asp.net? (El código de rboe también muestra cómo inyectar cosas (de la misma manera))


Ejemplo

private ILoginService _loginService; public override void OnActionExecuting(ActionExecutingContext context) { _loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService)); }

Espero eso ayude.


Si bien la pregunta se refiere implícitamente a "filtros a través de atributos", todavía vale la pena resaltar que agregar filtros "globalmente por tipo" es compatible con DI de fábrica:

[Para los filtros globales agregados por tipo] cualquier dependencia del constructor se completará mediante inyección de dependencia (DI) . Agregar un filtro por tipo es equivalente a los filtros. Agregar (nuevo TypeFilterAttribute (typeof (MyFilter))). https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection

Con respecto a los filtros basados ​​en atributos:

Los filtros que se implementan como atributos y se agregan directamente a las clases de controlador o métodos de acción no pueden tener dependencias de constructor proporcionadas por la inyección de dependencia (DI). Esto se debe a que los atributos deben tener sus parámetros de constructor suministrados donde se aplican. Esta es una limitación de cómo funcionan los atributos. https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection

Sin embargo, como se mencionó en las respuestas anteriores a la OP, hay formas de indirección que se pueden utilizar para lograr DI. En aras de la exhaustividad, aquí están los enlaces a los documentos oficiales:


Una forma más de resolver este problema. Puede obtener su servicio a través de Context como en el siguiente código:

public override void OnActionExecuting(ActionExecutingContext context) { _sessionService = context.HttpContext.RequestServices.GetService<ISessionService>(); if (_sessionService.LoggedInUser == null) { context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; context.Result = new JsonResult("Unauthorized"); } }

Tenga en cuenta que debe registrar este servicio en Startup.cs

services.AddTransient<ISessionService, SessionService>();


Usando estos artículos como referencia:

ASP.NET Core Action Filters

Filtros de acción, filtros de servicio y filtros de tipo en ASP.NET 5 y MVC 6

Usar el filtro como un ServiceFilter

Debido a que el filtro se usará como ServiceType , debe registrarse con el marco de trabajo IoC. Si los filtros de acción se usaran directamente, esto no sería necesario.

Startup.cs

public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddScoped<ISessionService, SessionService>(); services.AddScoped<EnsureUserLoggedIn>(); ... }

Se agregan filtros personalizados al método de controlador MVC y a la clase de controlador utilizando el atributo ServiceFilter manera:

[ServiceFilter(typeof(EnsureUserLoggedIn))] [Route("api/issues")] public class IssueController : Controller { // GET: api/issues [HttpGet] [ServiceFilter(typeof(EnsureUserLoggedIn))] public IEnumerable<string> Get(){...} }

Hubo otros ejemplos de

  • Usar el filtro como filtro global

  • Usando el filtro con controladores base

  • Usando el filtro con un pedido

Eche un vistazo, pruébelos y vea si eso resuelve su problema.

Espero que esto ayude.