将服务注入Action Filter

hyd*_*yde 55 c# dependency-injection .net-core asp.net-core

我试图将一个服务注入我的动作过滤器,但我没有在构造函数中注入所需的服务.这是我有的:

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而我正在装饰我的控制器:

[Route("api/issues"), EnsureUserLoggedIn]
public class IssueController : Controller
{
}
Run Code Online (Sandbox Code Playgroud)

Startup.cs

services.AddScoped<ISessionService, SessionService>();
Run Code Online (Sandbox Code Playgroud)

Nko*_*osi 66

使用这些文章作为参考:

ASP.NET核心动作过滤器

ASP.NET 5和MVC 6中的操作筛选器,服务筛选器和类型筛选器

将过滤器用作ServiceFilter

由于过滤器将用作a ServiceType,因此需要在框架IoC中注册.如果直接使用动作过滤器,则不需要这样做.

Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddMvc();

    services.AddScoped<ISessionService, SessionService>();
    services.AddScoped<EnsureUserLoggedIn>();

    ...
}
Run Code Online (Sandbox Code Playgroud)

自定义过滤器使用如下ServiceFilter属性添加到MVC控制器方法和控制器类:

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

还有其他例子

  • 使用过滤器作为全局过滤器

  • 使用带有基本控制器的过滤器

  • 使用带有订单的过滤器

看一看,试一试,看看是否能解决您的问题.

希望这可以帮助.

  • 如果需要在属性上指定属性,该如何工作? (2认同)

And*_*rei 30

全局过滤器

你需要实现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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Startup课堂上而不是注册实际过滤器,您注册过滤器工厂:

services.AddMvc(options =>
{
    options.Filters.Add(new AuthorizationFilterFactory());
});
Run Code Online (Sandbox Code Playgroud)


小智 25

解决此问题的另一种方法.您可以通过上下文获取服务,如下面的代码所示:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您必须在Startup.cs中注册此服务

services.AddTransient<ISessionService, SessionService>();
Run Code Online (Sandbox Code Playgroud)

  • 这可能有用,但它使用的服务定位器模式有时被认为是反模式 (3认同)
  • 对于我这个小调整来说,这看起来是最好的解决方案:var service = context.HttpContext.RequestServices.GetService(typeof(IMyService))as IMyService; (2认同)

Buk*_*mi 12

例子

private ILoginService _loginService;

public override void OnActionExecuting(ActionExecutingContext context)
        {
            _loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
        }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你。

  • 示例简单但直接。我一直在寻找的合适人选。通过使用 (T)context.HttpContext.RequestServices.GetService(typeof(T)) 它解决了依赖关系。好工作。 (2认同)

A.J*_*uer 9

阅读本文后,ASP.NET核心 - 真实世界的ASP.NET核心MVC过滤器(2016年8月)我实现了这样:

在Starup.cs/ConfigureServices中:

services.AddScoped<MyService>();
Run Code Online (Sandbox Code Playgroud)

在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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在MyFooController.cs中:

[MyFilter]
public IActionResult MyAction()
{
}
Run Code Online (Sandbox Code Playgroud)

编辑:传递参数[MyFilter("Something")]可以使用TypeFilterAttribute类的Arguments属性完成:如何在asp.net中的操作过滤器中添加参数?(rboe的代码也展示了如何注入东西(同样的方式))