ASP.NET Core 过滤器
大约 6 分钟约 1722 字
ASP.NET Core 过滤器
过滤器工作原理
过滤器在 ASP.NET Core 操作调用管道内运行。 过滤器管道在 ASP.NET Core 选择了要执行的操作之后运行:
不同过滤器类型在管道模型中的交互方式
过滤器作用域
以Attribute特性应用在Action上。
/// <summary>
/// 创建审批统计分类设置
/// </summary>
/// <param name="createDto"></param>
/// <returns></returns>
[HttpPost]
[Authorize("sys:approval:report:category:add")] //典型以Attribute特性应用在Action上
[LogRecord(LogEnum.CREATE)] //典型以Attribute特性应用在Action上
public async Task<CommonResult> CreateAsync([FromBody] CreateUpdateSysApprovalReportCategoryDto createDto)
{
ulong id = await _sysApprovalReportCategoryService.CreateAsync(createDto);
return CommonResult.CreateSuccess(id);
}
以Attribute特性应用在Controller上。
/// <summary>
/// 待办集成维护管理
/// </summary>
[ApiExplorerSettings(GroupName = "basic")]
[ApiController]
[Route(SystemConfig.RequestTodoPrefix + "third_todo_oam")]
[LoginAuthorizFilter] //典型以Attribute特性应用在Controller上
public class SysThirdTodoOAMController : Controller
{
}
以全局形式应用在Controller和Action上
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(option =>
{
option.Filters.Add<LoginAuthorizFilter>();
option.Filters.Add<GlobalExceptionFilter>();
option.Filters.Add<GlobalActionVerifyFilter>();
});
}
常用过滤器
Authorization filters 授权过滤器
{
/// <summary>
/// 功能权限授权验证
/// </summary>
public class LoginAuthorizFilter : Microsoft.AspNetCore.Authorization.AuthorizeAttribute, IAuthorizationFilter
{
/// <summary>
/// 授权验证
/// </summary>
/// <param name="context"></param>
public void OnAuthorization(AuthorizationFilterContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (!(context.ActionDescriptor is ControllerActionDescriptor))
{
return;
}
//匿名访问,不需要token认证、签名和登录
var allowanyone = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(typeof(IAllowAnonymous), true).Any()
|| controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(IAllowAnonymous), true).Any();
//自由逻辑
}
}
}
Resource filters 资源过滤器
// IResourceFilter
{
public class CustomResourceFilterAttribute : Attribute, IResourceFilter
{
private static Dictionary<string, object> CacheDictionary = new Dictionary<string, object>();
/// <summary>
/// 在XX资源之前执行
/// </summary>
/// <param name="context"></param>
public void OnResourceExecuting(ResourceExecutingContext context)
{
//throw new Exception("CustomResourceFilterAttribute异常了。。。。");
string key = context.HttpContext.Request.Path;
if (CacheDictionary.ContainsKey(key))
{
object oResult = CacheDictionary[key];
context.Result = (IActionResult)oResult;// context.Result 类似于一个断路器,只要对context.Result赋值,就不再继续往后执行了
}
Console.WriteLine("CustomResourceFilterAttribute.OnResourceExecuting");
}
/// <summary>
/// 在XX资源之后执行
/// </summary>
/// <param name="context"></param>
public void OnResourceExecuted(ResourceExecutedContext context)
{
string key = context.HttpContext.Request.Path;
CacheDictionary[key] = context.Result;
Console.WriteLine("CustomResourceFilterAttribute.OnResourceExecuted");
}
}
}
// IAsyncResourceFilter
{
public class CustomAsyncResourceFilterAttribute : Attribute, IAsyncResourceFilter
{
private static Dictionary<string, object> CacheDictionary = new Dictionary<string, object>();
/// <summary>
/// 在资源执行的时候
///
/// 扩展缓存:
/// 1.一组数据保存在内存中
/// 2.存储数据的标识---存数据---把标识附上去,取数据也可以通过这个标识直接去去
/// 3.缓存有数据,且标识不变---取到的缓存数据也不变
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
string key = context.HttpContext.Request.Path;
//在这里就应该检查缓存
//1.如果有缓存,就应该直接响应给前端了,不再继续往后,如果没有--就执行next.Invoke();
if (CacheDictionary.ContainsKey(key))
{
object oResult = CacheDictionary[key];
context.Result = (IActionResult)oResult;// context.Result 类似于一个断路器,只要对context.Result赋值,就不再继续往后执行了
}
else
{
ResourceExecutedContext executedContext = await next.Invoke(); //这里的执行就是去执行控制器的实例+Action方法
CacheDictionary[key] = executedContext.Result;
}
}
}
}
Action filters 操作过滤器
- 操作过滤器不应用于 Razor Pages。 Razor Pages 支持 IPageFilter 和 IAsyncPageFilter。
// IActionFilter
{
public class CustomActionFilterAttribute : Attribute, IActionFilter
{
/// <summary>
/// 在XXXAction执行之前
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
//如果在这里就判断一下,如果有匿名---就直接过去了,不让你走Filter
{
// context.ActionDescriptor.EndpointMetadata; //就是记录了要访问的当前的Action上标记的所有的特性
if (context.ActionDescriptor.EndpointMetadata.Any(f => f.GetType() == typeof(CustomAllowAnonymousAttribute)))
{
return;//如果标记的有这个特性,就返回了,不继续走后面的F
}
else
{
Console.WriteLine("CustomActionFilterAttribute.OnActionExecuting");
}
}
}
/// <summary>
/// 在XXAction执行之后
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.ActionDescriptor.EndpointMetadata.Any(f => f.GetType() == typeof(CustomAllowAnonymousAttribute)))
{
return;//如果标记的有这个特性,就返回了,不继续走后面的Filter的内容
}
else
{
Console.WriteLine("CustomActionFilterAttribute.OnActionExecuted");
}
}
}
}
//IAsyncActionFilter
{
public class CustomAsyncActionFilterAttribute : Attribute, IAsyncActionFilter
{
private ILogger<CustomAsyncActionFilterAttribute> _ILogger = null;
public CustomAsyncActionFilterAttribute(ILogger<CustomAsyncActionFilterAttribute> logger)
{
this._ILogger = logger;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
{
object controllerName = context.HttpContext.Request.RouteValues["controller"];
object actionName = context.HttpContext.Request.RouteValues["action"];
_ILogger.LogInformation($"{controllerName}--{actionName} 执行前。。");
}
await next.Invoke(); //就是去执行Action
{
object controllerName = context.HttpContext.Request.RouteValues["controller"];
object actionName = context.HttpContext.Request.RouteValues["action"];
_ILogger.LogInformation($"{controllerName}--{actionName} 执行后。。");
}
}
}
}
Exception filters 异常过滤器
{
public class CustomExceptionFilterAttribute : Attribute, IExceptionFilter
{
private IModelMetadataProvider _IModelMetadataProvider = null;
public CustomExceptionFilterAttribute(IModelMetadataProvider iModelMetadataProvider)
{
this._IModelMetadataProvider = iModelMetadataProvider;
}
/// <summary>
/// 当有异常的时候,就到这儿来
/// </summary>
/// <param name="context"></param>
public void OnException(ExceptionContext context)
{
// context.HttpContext;//Http请求的上下文。。得到HttpContext就可以;想要得到什么,这里都有
//进入都这里以后,就要在这里处理异常
//如何处理异常?
//1.判断异常是否被处理过
//2.如果没有处理---就处理
//3.异常处理完毕,就要指定当前异常已经被处理过了
if (!context.ExceptionHandled)// 如果没有处理-- - 就处理
{
//分情况讨论:请求的时候,响应的时候,可能会返回不同数据类型 View Json
if (IsAjaxRequest(context.HttpContext.Request)) //判断是否是Ajax请求--JSON
{
//返回一个JSON格式
context.Result = new JsonResult(new
{
Succeess = false,
Message = context.Exception.Message
});
}
else
{
//如果不是Ajax请求---返回一个友好的错误页面,告诉你说异常了,让你联系管理员去处理,而不是直接给黄页
ViewResult result = new ViewResult { ViewName = "~/Views/Shared/Error.cshtml" };
result.ViewData = new ViewDataDictionary(_IModelMetadataProvider, context.ModelState);
result.ViewData.Add("Exception", context.Exception);
context.Result = result; //断路器---只要对Result赋值--就不继续往后了;
}
}
context.ExceptionHandled = true;//异常已经被处理过了
Console.WriteLine("CustomExceptionFilterAttribute.OnException");
}
private bool IsAjaxRequest(HttpRequest request)
{
//HttpWebRequest httpWebRequest = null;
//httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");
string header = request.Headers["X-Requested-With"];
return "XMLHttpRequest".Equals(header);
}
}
}
//上述方法拦截异常,在ExceptionFilter之前的无法被拦截,可以在管道模型处理
#region 无法扑捉到的异常补充
app.UseExceptionHandler(configure =>
{
configure.Run(async context =>
{
var exHeader = context.Features.Get<IExceptionHandlerPathFeature>();
var ex = exHeader.Error;
ErrorResult result = new ErrorResult();
if (ex is ErrorException mycustomex)
{
result.errmsg = mycustomex.errmsg;
result.errcode = mycustomex.errcode;
}
else
{
result.errmsg = "程序异常,服务端出现异常![异常消息]" + ex.Message;
result.errcode = 500;
}
context.Response.StatusCode = 200;
context.Response.ContentType = "application/json; charset=utf-8";
await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(result.ToJson()));
});
});
#endregion
Result filters 结果过滤器
// IAlwaysRunResultFilter
{
public class CustomAlwaysRunResultFilterAttribute : Attribute, IAlwaysRunResultFilter
{
private ILogger<CustomAlwaysRunResultFilterAttribute> _ILogger = null;
public CustomAlwaysRunResultFilterAttribute(ILogger<CustomAlwaysRunResultFilterAttribute> logger)
{
this._ILogger = logger;
}
public void OnResultExecuting(ResultExecutingContext context)
{
_ILogger.LogInformation($"CustomAlwaysRunResultFilterAttribute-OnResultExecuting ");
}
public void OnResultExecuted(ResultExecutedContext context)
{
_ILogger.LogInformation($"CustomAlwaysRunResultFilterAttribute-OnResultExecuted ");
}
}
}
//IResultFilter
{
/// <summary>
/// 注册全局
/// </summary>
public class CustomResultFilterAttribute : Attribute, IResultFilter
{
private ILogger<CustomResultFilterAttribute> _ILogger = null;
public CustomResultFilterAttribute(ILogger<CustomResultFilterAttribute> logger)
{
this._ILogger = logger;
}
/// <summary>
/// 在结果执行执行之前
/// </summary>
/// <param name="context"></param>
public void OnResultExecuting(ResultExecutingContext context)
{
//ViewResult view = (ViewResult)context.Result;
//view.ViewData["StudentName"] = "超越自我。。。";
//Console.WriteLine("CustomResultFilterAttribute.OnResultExecuting:这里是视图、、渲染 Befor");
if (context.Result is JsonResult) //还有点小问题---大家自己处理一下
{
JsonResult jsonresult = (JsonResult)context.Result;
if (jsonresult.Value is not AjaxResult)
{
context.Result = new JsonResult(new AjaxResult()
{
Success = true,
Message = "OK",
Data = context.Result
});
}
}
}
/// <summary>
/// 在结果执行执行之之后
/// </summary>
/// <param name="context"></param>
public void OnResultExecuted(ResultExecutedContext context)
{
Console.WriteLine("CustomResultFilterAttribute.OnResultExecuted:这里是视图、、渲染 After");
}
}
public class AjaxResult
{
public bool Success { get; set; }
public string Message { get; set; }
public object Data { get; set; }
}
}
内置Attribute过滤器(抽象)
ActionFilterAttribute
{
public class CustomAllActionAndResultFilterAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
}
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
return base.OnActionExecutionAsync(context, next);
}
public override void OnResultExecuting(ResultExecutingContext context)
{
base.OnResultExecuting(context);
}
public override void OnResultExecuted(ResultExecutedContext context)
{
base.OnResultExecuted(context);
}
public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
return base.OnResultExecutionAsync(context, next);
}
}
}
ExceptionFilterAttribute
{
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
}
public override Task OnExceptionAsync(ExceptionContext context)
{
return base.OnExceptionAsync(context);
}
}
}
ResultFilterAttribute
{
public class CustomResultFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext context)
{
base.OnResultExecuted(context);
}
public override void OnResultExecuting(ResultExecutingContext context)
{
base.OnResultExecuting(context);
}
public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
return base.OnResultExecutionAsync(context, next);
}
}
}
FormatFilterAttribute
{
public class CustomFormatFilterAttribute : FormatFilterAttribute
{
}
}
辅助DI
应用场景:过滤器构造函数依赖其它实例化对象
ServiceFilterAttribute
注:此过滤器需di注入
[ServiceFilter(typeof(SignAuthorizeAttribute))]
public class SysThirdTodoController : Controller
{
}
TypeFilterAttribute
[TypeFilter(typeof(SignAuthorizeAttribute))]
public class SysThirdTodoController : Controller
{
}
IFilterFactory
{
public class CustomDIFactoryAttribute : Attribute, IFilterFactory
{
private Type _Type = null;
public CustomDIFactoryAttribute(Type type)
{
this._Type = type;
}
public bool IsReusable => true;
/// <summary>
/// CreateInstance: 创建实例
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
object oInstacne = serviceProvider.GetService(_Type);
return (IFilterMetadata)oInstacne;
}
}
}