【asp.net core 系列】10 实战之ActionFilter
0.前言
在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用。这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一下上一篇的工具类。
1. ActionFilter 介绍
ActionFilter全称是ActionFilterAttribute,我们根据微软的命名规范可以看出这是一个特性类,看一下它的声明:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IAsyncResultFilter, IOrderedFilter, IResultFilter
这是一个允许标注在类和方法上的特性类,允许多个标记,标注之后子类会继承父类的特性。然后,这个类是一个抽象类,所以我们可以通过继承ActionFilterAttribute来编写自己的ActionFilter。
1.1 ActionFilter的四个方法
对于一个ActionFilter而言,最重要的是它的四个方法:
public virtual void OnActionExecuted(ActionExecutedContext context);
public virtual void OnActionExecuting(ActionExecutingContext context);
public virtual void OnResultExecuted(ResultExecutedContext context);
public virtual void OnResultExecuting(ResultExecutingContext context);
上图是这四个方法在一次请求中执行的顺序。在一次请求真正执行之前,想要拦截这个请求,应该使用OnActionExecuting
。
为什么单独说这个呢?因为这个方法的出镜率很高,大多数时候都会使用这个方法进行请求过滤。
1.2 在ActionFilter中我们能做什么
我们来简单介绍一下,四个方法中的四种上下文类型,看一看里面有哪些我们可以利用的方法:
1.2.1 ActionExecutingContext
这是一个Action执行前的上下文,表示Action并未开始执行,但是已经获取到了控制器实例:
public class ActionExecutingContext : FilterContext
{
public virtual IDictionary<string, object> ActionArguments { get; }
public virtual object Controller { get; }
public virtual IActionResult Result { get; set; }
}
ActionExecutingContext继承自FilterContext,我们暂且不关注它的父类,只看一下它自己的属性。
- ActionArguments 表示Action的参数列表,这里面放着各种从用户接到请求参数以及其他中间处理程序添加的参数
- Controller 表示执行该请求的控制器,在之前我们提过,asp.net core 对于控制器的限制很小,所以控制器什么类型都可能,故而这里使用object作为控制器类型
- Result 执行结果,正常情况下,在此处获取这个属性的值没有意义。但是我们可以通过修改这个属性的值,来让我们拦截请求
1.2.2 ActionExecutedContext
ActionExecutedContext 表示Action执行完成后的上下文,这时候Action已经执行完成,我们可以通过这个获取Action执行结果:
public class ActionExecutedContext : FilterContext
{
public virtual bool Canceled { get; set; }
public virtual object Controller { get; }
public virtual Exception Exception { get; set; }
public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
public virtual bool ExceptionHandled { get; set; }
public virtual IActionResult Result { get; set; }
}
同样,继承自FilterContext,暂且忽略。
- Canceled 表示是否被设置短路
- Controller 处理请求的控制器
- Exception 执行过程中是否发生异常,如果有异常则 有值,否则为Null
- ExceptionHandled 异常是否被处理
- Result 此处对Result进行修改不会屏蔽执行的ActionResult,但是可以向用户隐藏对应的实现
1.2.3 ResultExecutingContext
这是在Result渲染之前执行的上下文,这时候Action已经执行完毕,正准备渲染Result:
public class ResultExecutingContext : FilterContext
{
public virtual bool Cancel { get; set; }
public virtual object Controller { get; }
public virtual IActionResult Result { get; set; }
}
- Cancel 取消当前结果执行以及后续筛选器的执行
- Controller 控制器
- Result 处理结果
1.2.4 ResultExecutedContext
Result已经执行完成了,获取执行结果上下文:
public class ResultExecutedContext : FilterContext
{
public virtual bool Canceled { get; set; }
public virtual object Controller { get; }
public virtual Exception Exception { get; set; }
public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
public virtual bool ExceptionHandled { get; set; }
public virtual IActionResult Result { get; }
}
这个类与 ActionExecutedContext类似,就不做介绍了。
1.2.5 FilterContext
在上面的四个上下文都继承自 FilterContext,那么我们来看一下FilterContext中有哪些属性或者方法:
public abstract class FilterContext : ActionContext
{
public virtual IList<IFilterMetadata> Filters { get; }
public TMetadata FindEffectivePolicy<TMetadata>() where TMetadata : IFilterMetadata;
}
可以看到FilterContext继承了另一个ActionContext的类。小伙伴们应该对这个类要有一定的概念,这个类是Action的上下文类。它完整存在于一个Action的生命周期,所以有时候可以通过ActionContext进行Action级的数据传递(不推荐)。
那么,继续让我们回过头来看看ActionContext里有什么:
public class ActionContext
{
public ActionDescriptor ActionDescriptor { get; set; }
public HttpContext HttpContext { get; set; }
public ModelStateDictionary ModelState { get; }
public RouteData RouteData { get; set; }
}
- ActionDescriptor 执行的Action描述信息,包括Action的显示名称、一些参数等,具体用到的时候,再为大伙详细说
- HttpContext 可以通过这个属性获取此次请求的Request和Response对象
- ModelState 模型校验信息, 这部分在后续再为小伙伴们细说
- RouteData 路由信息,asp.net core 在处理请求时解析出来的路由信息,包括在程序中修改的路由信息
2. 使用ActionFilter
在《【asp.net core 系列】9 实战之 UnitOfWork以及自定义代码生成》也就是上一篇中,介绍到了ActionFilter与普通特性类一致,可以通过标注控制器然后启用该ActionFilter。
因为大多数情况下,一个ActionFilter并不会仅仅局限于一个控制器,而是应用于多个控制器。所以这时候,我们通常会设置一个基础控制器,在这个控制器上进行标注,然后让子类继承这个控制器。通过这种方式来实现一次声明多次使用。
当然,在asp.net core 中添加了另外的一种使用ActionFilter的方式,Setup.cs中
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
默认是这样的,我们可以通过设置参数来添加一个全局应用的Filter,例如说我们上一篇中创建的 UnitOfWorkFilterAttribute:
services.AddControllersWithViews(options=>
{
options.Filters.Add<UnitOfWorkFilterAttribute>();
});
通过这种方式可以启用一个全局ActionFilter。如果需要使用asp.net core的默认依赖注入可以使用 AddService进行配置。(依赖注入的内容在后续会讲解)。
3. 工具类生成
继续上一篇遗留的内容:
public static void CreateEntityTypeConfig(Type type)
{
var targetNamespace = type.Namespace.Replace("Data.Models", "");
if (targetNamespace.StartsWith("."))
{
targetNamespace = targetNamespace.Remove(0);
}
var targetDir = Path.Combine(new[] { CurrentDirect, "Domain.Implements", "EntityConfigures" }.Concat(
targetNamespace.Split('.')).ToArray());
if (!Directory.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
var baseName = type.Name.Replace("Entity", "");
if (!string.IsNullOrEmpty(targetNamespace))
{
targetNamespace = $".{targetNamespace}";
}
var file = $"using {type.Namespace};" +
$"\r\nusing Microsoft.EntityFrameworkCore;" +
$"\r\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;" +
$"\r\nnamespace Domain.Implements.EntityConfigures{targetNamespace}" +
"\r\n{" +
$"\r\n\tpublic class {baseName}Config : IEntityTypeConfiguration<{type.Name}>" +
"\r\n\t{" +
"\r\n\t\tpublic void Configure(EntityTypeBuilder<SysUser> builder)" +
"\r\n\t\t{" +
$"\r\n\t\t\tbuilder.ToTable(\"{baseName}\");" +
$"\r\n\t\t\tbuilder.HasKey(p => p.Id);" +
"\r\n\t\t}\r\n\t}\r\n}";
File.WriteAllText(Path.Combine(targetDir, $"{baseName}Config.cs"), file);
}
工具类其实本质上就是一次文件写入的方法,本身没什么难度。
不过,这里还有有个小问题,每次调用都会覆盖原有的文件,还有就是这里面有很多可以优化的地方,小伙伴们可以自己试试去优化一下,让代码更好看一点。
4 总结
到目前为止,实战系列也有了几篇,很多小伙伴问我能提供一下源码吗?当然,能呀。不过不是现在,容我留个谜底。当主要框架功能完成之后,我就会给小伙伴们发代码的。
其实也是因为现在还没个完整的,开放给小伙伴们也没啥意义。当然了,跟着一块敲,也是能实现的哈。关键地方的代码都有。
更多内容烦请关注我的博客《高先生小屋》
【asp.net core 系列】10 实战之ActionFilter的更多相关文章
- asp.net core 系列 10 配置configuration (上)
一. ASP.NET Core 中的配置概述 ASP.NET Core 中的应用配置是基于键值对,由configuration 程序提供. configuration 将从各种配置源提供程序操作键 ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
- 【asp.net core 系列】6 实战之 一个项目的完整结构
0. 前言 在<asp.net core 系列>之前的几篇文章中,我们简单了解了路由.控制器以及视图的关系以及静态资源的引入,让我们对于asp.net core mvc项目有了基本的认识. ...
- 【asp.net core 系列】8 实战之 利用 EF Core 完成数据操作层的实现
0. 前言 通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口.这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方. 1. 添加EF Core 先 ...
- 1.1专题介绍「深入浅出ASP.NET Core系列」
大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...
- asp.net core系列 40 Web 应用MVC 介绍与详细示例
一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
- asp.net core系列 39 Web 应用Razor 介绍与详细示例
一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...
- asp.net core系列 36 WebAPI 搭建详细示例
一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...
随机推荐
- C#日志记录类
public class WriteLog { /// <summary> /// 将错误写入文件中 /// </summary> /// <param name=&qu ...
- 阿里短信回持.net sdk的bug导致生产服务cpu 100%排查
一:背景 1. 讲故事 去年阿里聚石塔上的所有isv短信通道全部对接阿里通信,我们就做了对接改造,使用阿里提供的.net sdk. 网址:https://help.aliyun.com/documen ...
- golang垃圾回收机制
golang的GC,1.8通过混合写⼊屏障, 使得STW降到了sub ms.go语言中程序代码执行和垃圾回收是并发执行的. 当前Go GC特征 :三色标记,并发标记和清扫,非分代,非紧缩,混合写屏障. ...
- 自己的win7第一次使用RabbitMQ
使用的过程中参考了https://www.cnblogs.com/longlongogo/p/6489574.html所写的内容 一.环境搭建 1.由于RabbitMQ使用Erlang语言编写,所以先 ...
- 动态生成Person类的对象 代码参考
#include <iostream> #include <string> using namespace std; class Person { private: strin ...
- Rocket - decode - Term
https://mp.weixin.qq.com/s/CbBWdTlc_DESlUzd8KFcSg 介绍Term类各方法的实现. 1. prime 表示一个项是否是质项,即这 ...
- MethodHandle(方法句柄)系列之一:MethodHandle和MethodType
阅读此文章的作者建议先了解java反射和动态代理. java7中为间接调用方法引入了新的api,其中最关键的是java.lang.invoke包,即方法句柄.我们可以看成是java ...
- Java实现 LeetCode 462 最少移动次数使数组元素相等 II
462. 最少移动次数使数组元素相等 II 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1. 您可以假设数组的长度最多为10000. 例如: 输 ...
- Java实现 LeetCode 260 只出现一次的数字 III(三)
260. 只出现一次的数字 III 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次. 找出只出现一次的那两个元素. 示例 : 输入: [1,2,1,3,2,5] 输出 ...
- Java实现 LeetCode 148 排序链表
148. 排序链表 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3-> ...