:::info

  1. 切面编程机制,在ASP.NET Core特定的位置执行我们自定义的代码。
  2. ASP.NET Core中的Filter的五种类型:Authorization Filter、Resource filter、Action filter、Exception filter、Result filter
  3. 所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口.
  4. OnAuthorization→OnResourceExecuting→创建控制器→OnActionExecuting→执行action业务→OnActionExecuted→OnResultExecuting→页面渲染加载→OnResultExecuted→OnResourceExecuted

:::

Exception

:::info

  1. 当系统中出现未处理异常的 时候,我们需要统一给客户返回一个友好的讯息:{“code”:”500”,”message”:”异常信息”}

:::

  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.AspNetCore.Mvc.Filters;
  3. namespace Filter1
  4. {
  5. //添加Attribute 是为了可以在当成特性添加到control或者Action上
  6. public class MyExceptionFilter : Attribute, IAsyncExceptionFilter
  7. {
  8. public Task OnExceptionAsync(ExceptionContext context)
  9. {
  10. // context.Exception代表异常信息对象
  11. //如果context.ExceptionHandled=true ,则其他 ExceptionFilter不会再执行
  12. // context.Result 的值会被输出到客户端
  13. string msg;
  14. msg = context.Exception.Message;
  15. ObjectResult result = new ObjectResult(new { code = 500, message = msg });
  16. context.Result = result;
  17. context.ExceptionHandled = true; // 表示当前异常被处理过
  18. Console.WriteLine("进入了异常");
  19. return Task.CompletedTask;
  20. }
  21. }
  22. }
  23. //全局注册使用
  24. using Microsoft.AspNetCore.Mvc;
  25. builder.Services.Configure<MvcOptions>(option =>
  26. {
  27. option.Filters.Add<MyExceptionFilter>();
  28. });

Action Filter

IActionFilter同步

定义Filter

  1. public class CustomerActionFilterAttribute : Attribute, IActionFilter
  2. {
  3. /// <summary>
  4. /// 在XXAction执行之前
  5. /// </summary>
  6. /// <param name="context"></param>
  7. public void OnActionExecuting(ActionExecutingContext context)
  8. {
  9. Console.WriteLine("CustomerActionFilterAttribute.OnActionExecuting");
  10. }
  11. /// <summary>
  12. /// 在XXAction执行之后
  13. /// </summary>
  14. /// <param name="context"></param>
  15. public void OnActionExecuted(ActionExecutedContext context)
  16. {
  17. Console.WriteLine("CustomerActionFilterAttribute.OnActionExecuted");
  18. }
  19. }

使用Filter

  1. //1. 全局注册Program.cs
  2. builder.Services.Configure<MvcOptions>(option =>
  3. {
  4. option.Filters.Add<MyExceptionFilter>();
  5. option.Filters.Add<CustomerActionFilterAttribute>();
  6. });
  7. //2.controller类或者Action方法注册
  8. public class Home1Controller : Controller
  9. {
  10. private readonly ILogger<HomeController> _logger;
  11. public Home1Controller(ILogger<HomeController> logger)
  12. {
  13. _logger = logger;
  14. Console.WriteLine($"执行 {this.GetType().Name} 构造函数");
  15. }
  16. [CustomerActionFilter]
  17. public IActionResult Index()
  18. {
  19. Console.WriteLine($"执行 Index 方法");
  20. return View();
  21. }
  22. }

扩展记录日志

  1. public class CustomerActionFilterAttribute : Attribute, IActionFilter
  2. {
  3. private readonly ILogger<CustomerActionFilterAttribute> _logger;
  4. public CustomerActionFilterAttribute(ILogger<CustomerActionFilterAttribute> _logger)
  5. {
  6. this._logger = _logger;
  7. Gid = Guid.NewGuid().ToString();
  8. }
  9. private string Gid; //用于测试他们执行一个Action是不是同一个对象
  10. public void OnActionExecuting(ActionExecutingContext context)
  11. {
  12. string ExecuteParam = "";
  13. string Executeurl = context.HttpContext.Request.Path;
  14. switch (context.HttpContext.Request.Method.ToUpper())
  15. {
  16. case "GET":
  17. ExecuteParam = context.HttpContext.Request.QueryString.Value.ToString();
  18. break;
  19. case "POST":
  20. Executeurl += context.HttpContext.Request.QueryString.Value.ToString();
  21. ExecuteParam = JsonConvert.SerializeObject(context.ActionArguments);
  22. break;
  23. default:
  24. break;
  25. }
  26. var controllerName = context.ActionDescriptor.RouteValues["controller"];
  27. var actionName = context.ActionDescriptor.RouteValues["action"];
  28. _logger.LogInformation($"当前请求的Url是{Executeurl},控制器是{controllerName},方法名{actionName},请求参数是{ExecuteParam},guid={Gid}");
  29. }
  30. public void OnActionExecuted(ActionExecutedContext context)
  31. {
  32. var para = (context.Result as ObjectResult).Value;
  33. var controllerName = context.ActionDescriptor.RouteValues["controller"];
  34. var actionName = context.ActionDescriptor.RouteValues["action"];
  35. _logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求结果是{JsonConvert.SerializeObject(para)},guid={Gid}");
  36. }

使用 扩展记录日志

  1. // 1.全局注册
  2. builder.Services.Configure<MvcOptions>(option =>
  3. {
  4. option.Filters.Add<MyExceptionFilter>();
  5. option.Filters.Add<CustomerActionFilterAttribute>();
  6. });
  7. //2.controller类或者Action方法注册
  8. [TypeFilter(typeof(CustomerActionFilterAttribute))]

IAsyncActionFilter(异步)

定义Filter

  1. public class CustomerAsyncActionFilterAttribute : Attribute, IAsyncActionFilter
  2. {
  3. private readonly ILogger<CustomerAsyncActionFilterAttribute> _logger;
  4. public CustomerAsyncActionFilterAttribute(ILogger<CustomerAsyncActionFilterAttribute> logger)
  5. {
  6. _logger = logger;
  7. }
  8. public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  9. {
  10. var para = context.HttpContext.Request.QueryString.Value;
  11. var controllerName = context.ActionDescriptor.RouteValues["controller"];
  12. var actionName = context.ActionDescriptor.RouteValues["action"];
  13. _logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求参数是{JsonConvert.SerializeObject(para)}");
  14. var excuteContext = await next.Invoke(); // 这句话就是去执行Action
  15. _logger.LogInformation($"当前请求的控制器是{controllerName},方法名{actionName},请求结果是{JsonConvert.SerializeObject(excuteContext.Result)}");
  16. }
  17. }

使用Filter

  1. public class Home1Controller : Controller
  2. {
  3. private readonly ILogger<HomeController> _logger;
  4. public Home1Controller(ILogger<HomeController> logger)
  5. {
  6. _logger = logger;
  7. Console.WriteLine($"执行 {this.GetType().Name} 构造函数");
  8. }
  9. //[TypeFilter(typeof(CustomerActionFilterAttribute))]
  10. [TypeFilter(typeof(CustomerAsyncActionFilterAttribute))] //注册
  11. public IActionResult Index(int id)
  12. {
  13. Console.WriteLine($"执行 Index 方法");
  14. ViewBag.Data = new { name = "11111" };
  15. return View();
  16. }
  17. }
  18. //全局注册Program.cs 也可以
  19. builder.Services.Configure<MvcOptions>(option =>
  20. {
  21. option.Filters.Add<MyExceptionFilter>();
  22. option.Filters.Add<CustomerAsyncActionFilterAttribute>();
  23. });

执行顺序

:::info

执行顺序: 1、执行控制器的构造函数 2、执行CustomerActionFilterAttribute.OnActionExecuting 3、执行Action方法

4、执行CustomerActionFilterAttribute.OnActionExecuted

:::

案例:对请求限速的ActionFilter

  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.AspNetCore.Mvc.Filters;
  3. using Microsoft.Extensions.Caching.Memory;
  4. namespace Filter1
  5. {
  6. public class RateLimitActionFilter : Attribute, IAsyncActionFilter
  7. {
  8. private readonly IMemoryCache memoryCache;
  9. public RateLimitActionFilter(IMemoryCache memoryCache)
  10. {
  11. this.memoryCache = memoryCache;
  12. }
  13. public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
  14. {
  15. string ip = context.HttpContext.Connection.RemoteIpAddress.ToString();
  16. string cacheKey = $"lastvisittick_{ip}";
  17. long? lastVisit = memoryCache.Get<long>(cacheKey);
  18. if (lastVisit == null || Environment.TickCount64 - lastVisit > 1000)
  19. {
  20. memoryCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));
  21. await next();
  22. }
  23. else
  24. {
  25. ObjectResult objectResult = new ObjectResult("访问太频繁") { StatusCode = 429 };
  26. context.Result = objectResult;
  27. }
  28. }
  29. }
  30. }
  31. //注入使用
  32. builder.Services.AddMemoryCache(); //添加ImemoryCache
  33. builder.Services.Configure<MvcOptions>(option =>
  34. {
  35. option.Filters.Add<RateLimitActionFilter>(); //全局注入
  36. option.Filters.Add<MyExceptionFilter>();
  37. option.Filters.Add<CustomerActionFilterAttribute>();
  38. });
  39. //也可以通过特性的方式单独添加到Action/controller上
  40. [TypeFilter(typeof(RateLimitActionFilter))]