[ASP.NET Core]ASP.NET Core应用程序开发中如何实现控制器中操作过滤属性的依赖注入?

ASP.NET Core 作者: Rector 21阅读 0评论 0收藏 收藏本文

郑重申明:本文未经许可,禁止任何形式转载

问题描述

在ASP.NET MVC的应用程序开发中,操作过滤属性是经常被使用到的。我们可以在操作过滤属性中拦截并处理当前操作的逻辑。

比如需要实现一个用户是否登录的操作过滤属性,它继承自ActionFilterAttribute,代码类似如下:

public class EnsureUserLoggedIn : ActionFilterAttribute
{
    private readonly ISessionService _sessionService;

    public EnsureUserLoggedIn()
    {
        // 如果移除了这个构造函数,会引发编译错误
    }

    public EnsureUserLoggedIn(ISessionService sessionService)
    {
        _sessionService = sessionService;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // 这里获取不到_sessionService的实例(_sessionService is null)
        if (_sessionService.LoggedInUser == null)
        {
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            context.Result = new JsonResult("Unauthorized");
        }
    }
}

控制器中的调用示例代码:

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

启动类Startup.cs配置如下:

services.AddScoped<ISessionService, SessionService>();

在ASP.NET Core应用程序开发中,我们应该如何向操作过滤属性中注入我们需要的服务实例呢?

方案一

由于过滤器作为ServiceType使用的,所以过滤器也需要注入到IoC的容器中。

Startup.cs

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

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

    ...
}

控制器使用ServiceFilter属性,如下:

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

方案二

使用全局过滤器(Global Filters)实现,只需要实现接口IFilterFactory即可,如下:

public class AuthorizationFilterFactory : IFilterFactory
{
    public bool IsReusable => false;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        // 通过IServiceProvider的`GetService`方法获取服务实例
        var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));
        return new AuthorizationFilter(context);
    }
}

之后,我们需要在启动类Startup.cs文件中添加一个全局的过滤器,如下:

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

方案三

我们还可以通过请求上下文来获取需要的服务实现实例,如下:

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");
    }
}

启动类Startup.cs配置依赖注入如下:

services.AddTransient<ISessionService, SessionService>();

这样,便可不用通过构造器注入所依赖的接口。

阅读了该文章的人还浏览了...

本文永久链接码友网 » [ASP.NET Core]ASP.NET Core应用程序开发中如何实现控制器中操作过滤属性的依赖注入?

发布于: 2018-10-29 09:26:50
分享扩散: