问题描述
在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>();
这样,便可不用通过构造器注入所依赖的接口。
版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。
发表评论
登录用户才能发表评论, 请 登 录 或者 注册