:::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.cs
builder.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(); //添加ImemoryCache
builder.Services.Configure<MvcOptions>(option =>
{
option.Filters.Add<RateLimitActionFilter>(); //全局注入
option.Filters.Add<MyExceptionFilter>();
option.Filters.Add<CustomerActionFilterAttribute>();
});
//也可以通过特性的方式单独添加到Action/controller上
[TypeFilter(typeof(RateLimitActionFilter))]