时间2020-04-18
AOP Filter
AOP可以让我们只需要关注业务逻辑的处理,负责一些公共模块的处理,
Core WebAPI Filter
一般过滤器↓
AuthorizeAttribute(授权过滤器)
IExceptionFilter,IAsyncExceptionFilter(异常过滤器)
ActionFilterAttribute,IActionFilter,IAsyncActionFilter(方法过滤器)
asp.net Core专属↓
ResourceFilter
步骤
在项目文件夹像下面新建一个名为Utility的文件夹,用于存放过滤器相关。
自定义一个资源过滤器的类。使用资源过滤器甚至可以改变绑定模型,还可以在资源过滤器中实现缓存以提高性能,
//Attribute用于将这个类标识为特性类,IResrouceFilter即实现资源过滤
public class CustomResourceFilterAttribute : Attribute, IResourceFilter
{//创建一个缓存字典
private static Dictionary<string, object> dicCache = new Dictionary<string, object>();
//该方法在Controller实例化之前执行
public void OnResourceExecuting(ResourceExecutingContext context)
{
//判断当前访问的api路径是否进行了缓存
string k = context.HttpContext.Request.Path.ToString();
if (dicCache.ContainsKey(k))
{
context.Result = dicCache[k] as ObjectResult;//Result短路器
}
}
//该方法在Action之后执行
public void OnResourceExecuted(ResourceExecutedContext context)
{
//添加缓存
string k = context.HttpContext.Request.Path.ToString();
var objResult = context.Result as ObjectResult;
dicCache[k] = objResult;
Console.WriteLine("添加缓存成功");
}
}
将其作为特性使用该过滤器。
ActionFilter
与其它过滤器不同的是ActionFilter有多种作用域,全局,局部(Controller),单个Action,单个方法使用的。
一、构造适用于单个Action的ActionFilter
首先我们有一个需求,用户访问某个Action的时候,我们将生成关于这个Action的日志文件,这就要求我们能在执行这个Action之前和之后分别对这个请求进行截获,然后写入日志。正好ActionFilter能在Action执行前后分别截获。
1.自定义一个ActionFilter的类,实现IActionFilter接口。(注意这个类要能实现日志写入),这里的ILogger接口,参考前面的Log4Net。
在Utilyty文件夹中新建一个名为CustomActionFilterAttribute 的类
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
public class CustomActionFilterAttribute : Attribute, IActionFilter
{
//Log配置
private ILogger<CustomActionFilterAttribute> _Logger;
public CustomActionFilterAttribute(ILogger<CustomActionFilterAttribute> logger)
{
_Logger = logger;
}
//利用Action做日志处理
//Action执行完毕调用该方法
public void OnActionExecuted(ActionExecutedContext context)
{
var objResult = context.Result as ObjectResult;
var actionEndLog = $"调用{context.RouteData.Values["action"]}api完毕,执行结果为:{Newtonsoft.Json.JsonConvert.SerializeObject(objResult.Value)}";
_Logger.LogInformation(actionEndLog);
}
//Action使用之前调用该方法
public void OnActionExecuting(ActionExecutingContext context)
{
var actionBeginLog = $"开始调用{context.RouteData.Values["action"]}api,参数为:{Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments)}";
_Logger.LogInformation(actionBeginLog);
}
}
将ActionResult作为特性使用的三种方式
方法1.TypeFilter,无需在IOC中注册,有自实现
方法2.ServiceFilter,需要在startup中针对该过滤器注册服务才能使用
方法3.自定义CustomIOCFilterFactoryAttribute实现,依然需要对过滤器进行服务注册
using MaRio.CoreProject.Utility;
using Microsoft.AspNetCore.Mvc;
[Route("myapi/[controller]")]
[ApiController]
//对全局的action过滤器生效--★Controller注册
//[CustomIOCFilterFactoryAttribute(typeof(CustomActionFilterAttribute))]
public class FirstController : ControllerBase
{
[Route("Info"), HttpGet]
//下面的特性含义:对单个action使用actionFilter制作使用日志;注意:不能直接用特性标注---★方法注册
//使用方法1.TypeFilter,不需要注册服务,TypeFilter有自实现
[TypeFilter(typeof(CustomActionFilterAttribute))]
//使用方法2.ServiceFilter,需要在startup中针对该过滤器注册服务才能使用
//[ServiceFilter(typeof(CustomActionFilterAttribute))]
//使用方法3.自定义CustomIOCFilterFactoryAttribute实现,依然需要对过滤器进行服务注册
//[CustomIOCFilterFactoryAttribute(typeof(CustomActionFilterAttribute))]
public string GetInfo()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(new
{
Id = 1,
Name = "小马"
});
}
}
通过观察TypeFilter和ServiceFilter发现两者均实现了一个的接口,实现其接口就可以实现和ServiceFilter一样的效果。实现步骤:1-新建一个CustomIOCFilterFactoryAttribute的类
using Microsoft.AspNetCore.Mvc.Filters;
using System;
public class CustomIOCFilterFactoryAttribute : Attribute, IFilterFactory
{
private Type _FilterType=null;
public CustomIOCFilterFactoryAttribute(Type type)
{
_FilterType = type;
}
public bool IsReusable => true;
/// <summary>
/// 在Core中对象的创建 都是通过IOC容器来创建
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return (IFilterMetadata)serviceProvider.GetService(this._FilterType);
}
}
可以看到其实现亦是通过服务的方式实现,由此,需要在starup.cs中进行服务注册
这样一来才能利用方法2或者3实现过滤器的功能
实现效果:当我们访问这个GetInfo接口的时候,在该方法执行前会对请求进行拦截进行一次操作的日志处理,方法调用完毕又做一次操作的日志处理。
我们对这个api发起请求
在日志里就会生成相应的操作记录
附:之前提到,ActionFilter有不同的作用范围,Filter特性的应用范围影响着该Filter的作用域。比如卸载某个Action上方则作用域是该Action,如果写在Controller上方,代表作用域为这个Controller,如果注册全局ActionFilter,则作用范围是全部的API。
全局注册的代码如下: