一、使用背景
过滤器有什么作用,在什么场景下适合用到它?
假设一个项目进展到快结束的时候,项目leader为了保证程序的稳定性和可监控和维护性要求将所有的方法加上日志,如果项目比较庞大,方法非常多,那岂不是得费很大得劲来完成这样一件事情。不过不用担心,咋们遇到的问题,伟大的语言设计者早已帮我们想好了解决办法过滤器,过滤器是一种AOP(面向切面编程)技术的体现,AOP具有松耦合,易扩展,代码可复用的特点。
通常我们在这些场景下如 身份验证 、 日志记录 、异常获取 等会使用到过滤器
二、分类
ASP.NET Core 有以下五种类型的过滤器,每个过滤器类型在过滤器管道中的不同阶段执行:
- Authorization Filter
授权过滤器 在过滤器管道中第一个执行,通常用于验证当前请求的合法性,不合法后面的管道会直接跳过。它们只有一个Before
方法,不像其它大多数过滤器支持前置阶段方法和后置阶段方法。注意,您不要在授权过滤器中抛出异常,因为没有任何代码来处理异常(异常过滤器不处理它们)。 - Resource Filter
资源过滤器是第二个运行,在 Authorization Filter 之后,Model Binding 之前执行。在性能方面,资源过滤器在实现缓存或截断过滤器管道尤为重要。 - Action Filter
使用率最高的过滤器,在调用 Acioin 方法之前和之后执行代码。跟 Resource Filter 很类似,但 Model Binding 在之后执行。 - Exception Filter
用于为应用程序执行异常处理策略。 - Result Filter
当 Action 执行完成后,最后会执行过滤器。用于处理ActionResult结果输出策略。
三、 运行顺序(生命周期)
注释:黃色箭头是正常情況流程;灰色箭头是异常处理流程;
四、使用
1、
public class GlobalFiler: Attribute,IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
context.Result = new JsonResult("全局权限设置");
}
}
public class MyFilter : Attribute,IActionFilter,IOrderedFilter
{
public int Order { get; set; }
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}
//ActionFilterAttribute继承了Attribute、IActionFilter、IOrderedFilter等
public class MyFilter2 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
//如果失败,页面提示
context.Result = new JsonResult("MyFilter2设置,无权限访问");
}
}
2、 过滤器注册,分为两种:全局注册和用Attribute区域注册,用在特定Action上。
1)全局注册Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config => config.Filters.Add(new GlobalFiler()));
//services.AddMvc(config => config.Filters.Add(typeof(GlobalFiler)));
}
2)区域注册
[Route("api/[controller]")]
[MyFilter(Order = 1)]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
[MyFilter2(Order = 0)]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
五、案例
1.日志
public class LogFilter : ActionFilterAttribute
{
private const string Key = "action";
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
var httpContext = context.HttpContext;
var stopwach = httpContext.Items[Key] as Stopwatch;
stopwach.Stop();
var time = stopwach.Elapsed;
string res = string.Empty;
if (context.Result is OkObjectResult)
{
var jsonResult = context.Result as OkObjectResult;
res = JsonConvert.SerializeObject(jsonResult.Value);
}
if (context.Result is ObjectResult)
{
var jsonResult = context.Result as ObjectResult;
res = JsonConvert.SerializeObject(jsonResult.Value);
}
LogHelper.Info($"请求结束时间:{DateTime.Now}地址:{context.HttpContext.Request.Path}响应:{res}耗时:{time.ToString()}");
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
string req = string.Empty;
if (context.ActionArguments.Values is ICollection<object>)
{
var jsonreq = context.ActionArguments.Values as ICollection<object>;
req = JsonConvert.SerializeObject(jsonreq.FirstOrDefault());
}
LogHelper.Info($"请求开始时间:{DateTime.Now}地址:{context.HttpContext.Request.Path }参数:{req}");
var stopwach = new Stopwatch();
stopwach.Start();
context.HttpContext.Items.Add(Key, stopwach);
}
}
六、参考文章
https://www.cnblogs.com/tdfblog/p/filters-in-aspnet-core-mvc.html
https://www.cnblogs.com/flywing/p/8692596.html
https://blog.51cto.com/14465598/2447871
七、补充
Filters的执行顺序?
参考文章:https://www.cnblogs.com/lijingran/p/6420397.html
https://blog.csdn.net/zxd1435513775/article/details/80556034
https://www.cnblogs.com/minskiter/p/11601873.html
首先有,OnExecuting和OnExecuted之分
还有 action、controller、Global之分
个人仅测试了日志过滤器和token过滤器,两者继承了ActionFilterAttribute类,
顺序和这里注册的顺序有关。