:::info
- 切面编程机制,在ASP.NET Core特定的位置执行我们自定义的代码。
- ASP.NET Core中的Filter的五种类型:Authorization Filter、Resource filter、Action filter、Exception filter、Result filter
- 所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口.
- OnAuthorization→OnResourceExecuting→创建控制器→OnActionExecuting→执行action业务→OnActionExecuted→OnResultExecuting→页面渲染加载→OnResultExecuted→OnResourceExecuted
:::
Exception
:::info
- 当系统中出现未处理异常的 时候,我们需要统一给客户返回一个友好的讯息:{“code”:”500”,”message”:”异常信息”}
:::
using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;namespace Filter1{//添加Attribute 是为了可以在当成特性添加到control或者Action上public class MyExceptionFilter : Attribute, IAsyncExceptionFilter{public Task OnExceptionAsync(ExceptionContext context){// context.Exception代表异常信息对象//如果context.ExceptionHandled=true ,则其他 ExceptionFilter不会再执行// context.Result 的值会被输出到客户端string msg;msg = context.Exception.Message;ObjectResult result = new ObjectResult(new { code = 500, message = msg });context.Result = result;context.ExceptionHandled = true; // 表示当前异常被处理过Console.WriteLine("进入了异常");return Task.CompletedTask;}}}//全局注册使用using Microsoft.AspNetCore.Mvc;builder.Services.Configure<MvcOptions>(option =>{option.Filters.Add<MyExceptionFilter>();});
Action Filter
IActionFilter同步
定义Filter
public class CustomerActionFilterAttribute : Attribute, IActionFilter{/// <summary>/// 在XXAction执行之前/// </summary>/// <param name="context"></param>public void OnActionExecuting(ActionExecutingContext context){Console.WriteLine("CustomerActionFilterAttribute.OnActionExecuting");}/// <summary>/// 在XXAction执行之后/// </summary>/// <param name="context"></param>public void OnActionExecuted(ActionExecutedContext context){Console.WriteLine("CustomerActionFilterAttribute.OnActionExecuted");}}
使用Filter
//1. 全局注册Program.csbuilder.Services.Configure<MvcOptions>(option =>{option.Filters.Add<MyExceptionFilter>();option.Filters.Add<CustomerActionFilterAttribute>();});//2.controller类或者Action方法注册public class Home1Controller : Controller{private readonly ILogger<HomeController> _logger;public Home1Controller(ILogger<HomeController> logger){_logger = logger;Console.WriteLine($"执行 {this.GetType().Name} 构造函数");}[CustomerActionFilter]public IActionResult Index(){Console.WriteLine($"执行 Index 方法");return View();}}
扩展记录日志
public class CustomerActionFilterAttribute : Attribute, IActionFilter{private readonly ILogger<CustomerActionFilterAttribute> _logger;public CustomerActionFilterAttribute(ILogger<CustomerActionFilterAttribute> _logger){this._logger = _logger;Gid = Guid.NewGuid().ToString();}private string Gid; //用于测试他们执行一个Action是不是同一个对象public void OnActionExecuting(ActionExecutingContext context){string ExecuteParam = "";string Executeurl = context.HttpContext.Request.Path;switch (context.HttpContext.Request.Method.ToUpper()){case "GET":ExecuteParam = context.HttpContext.Request.QueryString.Value.ToString();break;case "POST":Executeurl += context.HttpContext.Request.QueryString.Value.ToString();ExecuteParam = JsonConvert.SerializeObject(context.ActionArguments);break;default:break;}var controllerName = context.ActionDescriptor.RouteValues["controller"];var actionName = context.ActionDescriptor.RouteValues["action"];_logger.LogInformation($"当前请求的Url是{Executeurl},控制器是{controllerName},方法名{actionName},请求参数是{ExecuteParam},guid={Gid}");}public void OnActionExecuted(ActionExecutedContext context){var para = (context.Result as ObjectResult).Value;var controllerName = context.ActionDescriptor.RouteValues["controller"];var actionName = context.ActionDescriptor.RouteValues["action"];_logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求结果是{JsonConvert.SerializeObject(para)},guid={Gid}");}
使用 扩展记录日志
// 1.全局注册builder.Services.Configure<MvcOptions>(option =>{option.Filters.Add<MyExceptionFilter>();option.Filters.Add<CustomerActionFilterAttribute>();});//2.controller类或者Action方法注册[TypeFilter(typeof(CustomerActionFilterAttribute))]
IAsyncActionFilter(异步)
定义Filter
public class CustomerAsyncActionFilterAttribute : Attribute, IAsyncActionFilter{private readonly ILogger<CustomerAsyncActionFilterAttribute> _logger;public CustomerAsyncActionFilterAttribute(ILogger<CustomerAsyncActionFilterAttribute> logger){_logger = logger;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){var para = context.HttpContext.Request.QueryString.Value;var controllerName = context.ActionDescriptor.RouteValues["controller"];var actionName = context.ActionDescriptor.RouteValues["action"];_logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求参数是{JsonConvert.SerializeObject(para)}");var excuteContext = await next.Invoke(); // 这句话就是去执行Action_logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求结果是{JsonConvert.SerializeObject(excuteContext.Result)}");}}
使用Filter
public class Home1Controller : Controller{private readonly ILogger<HomeController> _logger;public Home1Controller(ILogger<HomeController> logger){_logger = logger;Console.WriteLine($"执行 {this.GetType().Name} 构造函数");}//[TypeFilter(typeof(CustomerActionFilterAttribute))][TypeFilter(typeof(CustomerAsyncActionFilterAttribute))] //注册public IActionResult Index(int id){Console.WriteLine($"执行 Index 方法");ViewBag.Data = new { name = "11111" };return View();}}//全局注册Program.cs 也可以builder.Services.Configure<MvcOptions>(option =>{option.Filters.Add<MyExceptionFilter>();option.Filters.Add<CustomerAsyncActionFilterAttribute>();});
执行顺序
:::info
执行顺序: 1、执行控制器的构造函数 2、执行CustomerActionFilterAttribute.OnActionExecuting 3、执行Action方法4、执行CustomerActionFilterAttribute.OnActionExecuted
:::
案例:对请求限速的ActionFilter
using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;using Microsoft.Extensions.Caching.Memory;namespace Filter1{public class RateLimitActionFilter : Attribute, IAsyncActionFilter{private readonly IMemoryCache memoryCache;public RateLimitActionFilter(IMemoryCache memoryCache){this.memoryCache = memoryCache;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){string ip = context.HttpContext.Connection.RemoteIpAddress.ToString();string cacheKey = $"lastvisittick_{ip}";long? lastVisit = memoryCache.Get<long>(cacheKey);if (lastVisit == null || Environment.TickCount64 - lastVisit > 1000){memoryCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));await next();}else{ObjectResult objectResult = new ObjectResult("访问太频繁") { StatusCode = 429 };context.Result = objectResult;}}}}//注入使用builder.Services.AddMemoryCache(); //添加ImemoryCachebuilder.Services.Configure<MvcOptions>(option =>{option.Filters.Add<RateLimitActionFilter>(); //全局注入option.Filters.Add<MyExceptionFilter>();option.Filters.Add<CustomerActionFilterAttribute>();});//也可以通过特性的方式单独添加到Action/controller上[TypeFilter(typeof(RateLimitActionFilter))]
