WebApi 过滤器
Authorization Filters //权限验证
Resource Filters //资源验证 常被用于缓存
Model Binding //模型绑定
Action Filters //行为 常被用于模型验证和日志记录
Exception Filters //异常处理 常被用于错误日志
Result Filters //结果验证 用于
三种注册方式
- 方法注册 注册在方法上 Action
- 类注册 注册在控制器上 Controller
- 全局注册 注册在Program
过滤器的注解的定义
public class CtmResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
throw new NotImplementedException();
}
//控制器请求前,可以有效减少服务器的压力
public void OnResourceExecuting(ResourceExecutingContext context)
{
//可以添加短路器
throw new NotImplementedException();
}
}
public class CtmAuthriztionFuilterAttribute : Attribute, IAuthorizationFilter
{
//在请求完成前
public void OnAuthorization(AuthorizationFilterContext context)
{
throw new NotImplementedException();
}
}
public class CtmActionFilterAttribute : Attribute, IActionFilter
{
//请求结束后
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
//请求结束前
public void OnActionExecuting(ActionExecutingContext context)
{
throw new NotImplementedException();
}
}
三种方法权重不一样,执行的依次顺序
progarm->类注册->方法注册
相同类型的FIlter,全局注册的优先级>类上注册优先级>方法上的优先级
不同类型的拦截器互不影响,按照图例顺序
方法注册
namespace FilterDemo.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
[CtmActionFilter]//行为拦截
[CtmAuthriztionFuilter]//鉴权
public string Get()
{
return "";
}
}
}
类注册
namespace FilterDemo.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
[CtmActionFilter]//行为拦截
[CtmAuthriztionFuilter]//鉴权
[CtmResourceFilter]//资源拦截
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public string Get()
{
return "";
}
}
}
Progarm注册
builder.Services.AddControllers(o=>o.Filters.Add<CtmActionFilterAttribute>());
builder.Services.AddControllers(o=> {
//数字越小,越先执行
o.Filters.Add<CtmActionFilterAttribute>(1);
o.Filters.Add<CtmActionFilterAttribute>(2);
});
过滤器的执行顺序
在方法注册上添加order比重
[HttpGet]
// [CtmActionFilter]//行为拦截
[CtmAuthriztionFuilter]//鉴权
[TypeFilter(typeof(CtmResourceFilterAttribute))]//资源拦截
[TypeFilter(typeof(CtmExceptionFilterAttriubute))]//异常处理拦截
[CtmResultFilter]
//在特性中,第一个是作为构造函数传入的,第二个是给属性传参,要把属性的名称填上
[TypeFilter(typeof(CtmActionFilterAttribute),Order =1)]
public string Get()
{
return "";
}
就算是全局定义的filter,如果自行定义的order没有方法注册的比重大,那么,仍然要先执方法注册的
授权过滤器
AuthorizationFilter
过滤器管道中的第一个过滤器。
控制对操作方法的访问。
这是一个简单的模拟,目的是拿取参数中的值
短路器
前置过滤器有AuthorizationFilter和ResouceFilter,这两个过滤器是指在控制器的构造函数执行之前执行的,这两个过滤器执行后,执行构造函数,在执行Model Binding模型绑定和ActionFilter
ResourceFilter
其中Result正常来说为null,如果不等于null,正常来说,应该是短路器被触发了。
短路器被触发后,就不会去触发控制器的构造函数了,会直接通过短路器的内部逻辑返回请求。
public class CtmResourceFilterAttribute : Attribute, IResourceFilter
{
private static Dictionary<string, object> _dicCache = new Dictionary<string, object>();
//控制器处理请求后
public void OnResourceExecuted(ResourceExecutedContext context)
{
//获取当前访问的网址
PathString path = context.HttpContext.Request.Path;
//将返回的数据存在数组中
_dicCache[path] = context.Result as ObjectResult;
}
//控制器请求前,可以有效减少服务器的压力
public void OnResourceExecuting(ResourceExecutingContext context)
{
//可以添加短路器,这里就触发短路了
//context.Result = new JsonResult("没有权限");
//获取当前的访问地址
var path = context.HttpContext.Request.Path;
//字典中是否包含path
if (_dicCache.ContainsKey(path))
{
//如果包含,直接返回缓存的数据
context.Result = _dicCache[path] as ObjectResult;
}
}
}
ActionFilter
用于 记录日志,模型认证
以下代码讲的是,如何用ActionFilter去记录日志和特性注入
过滤器实现构造函数注入
[HttpPost]
[TypeFilter(typeof(CtmActionFilterAttribute))]
public User AddUser(User user)
{
return user;
}
//一个特性,关于方法的拦截
public class CtmActionFilterAttribute : Attribute, IActionFilter
{
private readonly ILogger logger;
public CtmActionFilterAttribute(ILogger<CtmActionFilterAttribute> logger)
{
this.logger = logger;
}
//请求结束后
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
//请求结束前
public void OnActionExecuting(ActionExecutingContext context)
{
logger.LogInformation("....");
}
}
还有一种注册方式
[HttpPost]
[ServiceFilter(typeof(CtmActionFilterAttribute))]
public User AddUser(User user)
{
return user;
}
这种方式需要将filter在Progarm中进行依赖注册
builder.Services.AddTransient<CtmActionFilterAttribute>();
//这里注册的是Transient,瞬态
如果使用了ServiceFilter,那么无论是Filter本身还是filter需要注入的参数,都需要在容器中注入。
builder.Services.AddTransient<User>();
public class CtmActionFilterAttribute : Attribute, IActionFilter
{
private readonly ILogger logger;
private readonly User user;
public CtmActionFilterAttribute(ILogger<CtmActionFilterAttribute> logger,User user)
{
this.logger = logger;
this.user = user;
}
//请求结束后
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
//请求结束前
public void OnActionExecuting(ActionExecutingContext context)
{
PathString path = context.HttpContext.Request.Path;
var argumnet = context.ActionArguments;
if (argumnet.ContainsKey("User"))
{
var user = argumnet["user"] as User;
logger.LogInformation($"{user.Name} is visiting {path}");
}
else
{
logger.LogInformation($"{user.Name} is visiting {path}");
}
}
利用缓存实现短路
缓存使用menory catch
首先要对menory catch进行注册
注意注册时,不能用瞬态,使用单例模式,保持缓存的存在
builder.Services.AddSingleton<IMemoryCache,MemoryCache>();
对控制器使用
[HttpGet]
// [CtmActionFilter]//行为拦截
[CtmAuthriztionFuilter]//鉴权
[TypeFilter(typeof(CtmResourceFilterAttribute))]//资源拦截
public string Get()
{
return "";
}
这样才能在ResourceFilterAttribute中拿到相应的缓存
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
namespace FilterDemo.Filters
{
public class CtmResourceFilterAttribute : Attribute, IResourceFilter
{
private static Dictionary<string, object> _dicCache = new Dictionary<string, object>();
private readonly IMemoryCache memoryCache;
//控制器处理请求后
public CtmResourceFilterAttribute(IMemoryCache memoryCache)
{
this.memoryCache = memoryCache;
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
/* //获取当前访问的网址
PathString path = context.HttpContext.Request.Path;
//将返回的数据存在数组中
_dicCache[path] = context.Result as ObjectResult;*/
//获取当前访问的网址
PathString path = context.HttpContext.Request.Path;
//不再用字典,用缓存进行存储返回的结果
//两个参数,一个key一个value
memoryCache.Set(path, context.Result as ObjectResult);
}
//控制器请求前,可以有效减少服务器的压力
public void OnResourceExecuting(ResourceExecutingContext context)
{
//可以添加短路器,这里就触发短路了
//context.Result = new JsonResult("没有权限");
//获取当前的访问地址
var path = context.HttpContext.Request.Path;
//字典中是否包含path
/* if (_dicCache.ContainsKey(path))
{
//如果包含,直接返回缓存的数据
context.Result = _dicCache[path] as ObjectResult;
}*/
//从缓存中拿到当前path对应的值
//有值返回true,没有值返回false
if(memoryCache.TryGetValue(path,out object value))
{
context.Result = value as ObjectResult;
}
}
}
}
关于out
if(memoryCache.TryGetValue(path,out object value))
{
context.Result = value as ObjectResult;
}
解析版
object value;
if(memoryCache.TryGetValue(path,out value))
{
context.Result = value as ObjectResult;
}
给参数赋值后,加上out,可以将返回值,和加上out修饰的值一并带出来。
ExceptionFilters
异常处理拦截
作用是捕获异常的处理
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace FilterDemo.Filters
{
public class CtmExceptionFilterAttriubute : Attribute, IExceptionFilter
{
private readonly ILogger<CtmExceptionFilterAttriubute> logger;
public CtmExceptionFilterAttriubute(ILogger<CtmExceptionFilterAttriubute> logger)
{
this.logger = logger;
}
//在这里可以拿到错误信息
public void OnException(ExceptionContext context)
{
logger.LogInformation(context.Exception.Message);
context.Result = new ContentResult
{
Content = context.Exception.Message
};
}
}
}
[HttpGet]
// [CtmActionFilter]//行为拦截
[CtmAuthriztionFuilter]//鉴权
[TypeFilter(typeof(CtmResourceFilterAttribute))]//资源拦截
[TypeFilter(typeof(CtmExceptionFilterAttriubute))]//异常处理拦截
public string Get()
{
return "";
}
异常过滤器的捕获范围
可以用于常见的错误处理策略
非常适合捕获发生在操作中的异常
建议使用中间件的处理异常
基于所调用的操作方法,仅当错误处理不同时,才使用异常过滤器。
只能捕获跟action相关的异常,只能捕获操作相关的异常
捕获范围很小
ResultFilters
结果过滤器,围绕着操作结果执行。
只有当操作能够生成结果时,才会使用结果过滤器。
在异常过滤器通过生成操作结果时,结果过滤器不会执行。
结果过滤器中的异常不会被异常过滤器捕获
但是如果继承了IAlwaysRunResultFilter接口,那么就可以在异常过滤器捕获异常后仍然可以进入结果过滤器
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace FilterDemo.Filters
{
public class CtmAlwaysResultFilter : Attribute, IAlwaysRunResultFilter
{
public void OnResultExecuted(ResultExecutedContext context)
{
throw new NotImplementedException();
}
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is StatusCodeResult statusCodeResult
&& statusCodeResult.StatusCode == StatusCodes.Status404NotFound)
{
context.Result = new ObjectResult("这是404")
{
StatusCode = StatusCodes.Status404NotFound
};
}
}
}
}
标签:WebApi,void,学习,context,过滤器,path,logger,public
From: https://www.cnblogs.com/guan-tou6/p/18234380