【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服务可以覆盖广泛的客户端,包括浏 ...
随机推荐
- Android | 超简单集成HMS ML Kit实现最大脸微笑抓拍
前言 如果大家对HMS ML Kit 人脸检测功能有所了解,相信已经动手调用我们提供的接口编写自己的APP啦.目前就有小伙伴在调用接口的过程中反馈,不太清楚HMS ML Kit 文档中的MLMax ...
- python - 怎样使用 requests 模块发送http请求
最近在学python自动化,怎样用python发起一个http请求呢? 通过了解 request 模块可以帮助我们发起http请求 步骤: 1.首先import 下 request 模块 2.然后看请 ...
- Java并没有衰落.大家对它的认识才刚刚开始 Java8全新出发
Java并没有衰落.大家对它的认识才刚刚开始 很高兴能在此给大家分享Java8的新特性.这篇文章将一步一步带你了解Java8的所有新特性.我将通过简单的实例代码向大家展示接口中默认方法,lambda ...
- abp(net core)+easyui+efcore实现仓储管理系统——出库管理之一(四十九)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...
- 线程池续:你必须要知道的线程池submit()实现原理之FutureTask!
前言 上一篇内容写了Java中线程池的实现原理及源码分析,说好的是实实在在的大满足,想通过一篇文章让大家对线程池有个透彻的了解,但是文章写完总觉得还缺点什么? 上篇文章只提到线程提交的execute( ...
- vscode jshint 报'import' is only available in ES6 (use 'esversion: 6'). (W119)错误
vue项目用vscode打开代码前出现黄点,js报错 'import' is only available in ES6 (use 'esversion: 6'). (W119) 意思是import属 ...
- Java实现蓝桥杯算法提高P0102
算法提高 P0102 时间限制:1.0s 内存限制:256.0MB 提交此题 用户输入三个字符,每个字符取值范围是0-9,A-F.然后程序会把这三个字符转化为相应的十六进制整数,并分别以十六进制,十进 ...
- Java实现 蓝桥杯 历届试题 核桃的数量
历届试题 核桃的数量 时间限制:1.0s 内存限制:256.0MB 问题描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑).他的 ...
- Java实现 洛谷 P1090 合并果子
import java.io.BufferedInputStream; import java.util.Arrays; import java.util.Scanner; public class ...
- java实现第七届蓝桥杯反幻方
反幻方 题目描述 我国古籍很早就记载着 2 9 4 7 5 3 6 1 8 这是一个三阶幻方.每行每列以及对角线上的数字相加都相等. 下面考虑一个相反的问题. 可不可以用 1~9 的数字填入九宫格. ...