开始
解决上节课put和delete的问题
上节课的小尾巴没讲的put和delete的问题。
后端这里也放开
之前不能访问的原因是由于不能跨域,加上传输的数据格式不对,就会发生put和delete不能访问的问题。
现在我们把跨域和apiController都加上了。
加上断点测试。
上节课已经设置了跨域
put
进入断点
delete也进入断点了
httpGet请求传多个参数
1和ace
参数和参数之间用横线也是可以的
路由Route加到action上
输入home/16
把最上面的Route注释掉,只用第一个Action的Route
把其他方法都注释掉。以免引起错误。
路径后面直接传一个1
本节课开始-过虑器
创建测试项目
双击Form。在Form加载时候使用
在form加载时使用,直接拿过来
i小于10才能弹窗。这样无疑给我的getInfo方法增加了权限的配置。这样对getInfo方法单一的职责产生了污染。本来职责就是弹个窗
不希望getInfo单一的逻辑产生污染。那就在没有到getInfo的时候先做判断。
aop的注册方式
有3中注册方式。
1,方法上注册
2.类上面注册
3.全局注册、
创建Filters文件夹
创建类
实现接口Attribute,只有加上这个接口,我的类才可以在方法或者类上面加这个特性。
这样就可以做为一个特性加到方法上面去了。
再继承IActionFilter才可以面向切面。
实现里面的接口
打开另外一个演示demo
继承了这俩之后,
权限的判断,如果没有权限就显示Form4
Form4里面
label改成您没有权限
启动程序测试
弹出了Form4。Form2就没法再打开了。
注释掉这句话
点击按钮打开就是Form2
继续
下面我们要做日志的输出
运行测试,报错
这里的action已经加上了这个Attribute
移到最下面
路由也先去掉了。
运行程序测试,还是有这个错误
把Route路由再放开注释,
因为下面的这些方法都没有加路由,所以必须要有一个路由。
控制台没有输出
这里加上断点
再来测试
进入了断点。
走过了console的代码
用cmd窗体那种启动项目的方式会输出到控制台,因为我们这里不是在控制台,所以看不到输出的信息,
后面我们应写日志的方式输出。
类上使用
在类上使用无论是调用哪个Action都会进入filter
进入了断点。OnActionExecuting方法内。
然后会进入Action的方法内。
方法再走完,会进入到OnActionExecuted方法内。
对我们的delte方法同样有用。
因为我们的特性直接加载Controller上的,所以里面所有方法都可以使用这个Attribute
中间件中注册Aop
注册服务是对全局使用
在AddControllers里面注册,使用o.FIlters.Add 里面不能直接写我们的Filter
里面接收的是一个FilterType
所以这里我们要写上typeof里面是我们的filter
测试。这样无论访问哪个方法都会触发
启动测试,打开默认的页面时候就触发了。
因为我们在项目最初调用的就是这个,在这个里面会重定向到我们的swagger里面。
走完filter里面两个方法后,才会进去swagger页面。
在注册aop的filter的顺序是什么?
方法、类、全局注册。
先走到全局、再走到类里面、再走到中间方法里面。
创建全局Filter
添加一个Global的
把我们之前的filter的代码 全复制过来。
把Global的Filter全局注册。
原来的还是在Controller里面使用。
分别在这两个Filter上加上断点
启动程序,默认就走到了全局这里
全局走完打开了首页。
先走的全局
然后到了普通的filter的 OnActionExecuting
再走,到了具体的action方法
走完之后到了。普通的filter的OnActionExecuted
再走到了全局的OnActionExecuted
类似于这个结构,最上面是全局的Executing 最下面是全局的Executed。
中间生菜 上面生菜是类的Executing ,下面生菜是类的Executed。
最中间的肉是action方法。
这个是dotnet的mvc和webapi的管道模型。
dotnetCore的管道模型
要结合着下面这个来看。下面这个是中间件。中间件类似一个俄罗斯套娃。先进去后出。
Config里面有很多的app.Use 这些都是中间件。
中间件的顺序也是 先进去,最后再出来。先进的后出。
跨域一定要写在Routing的下面。如果写在前面,路由还在没加载呢 就要跨域肯定是没用的。
Module binding是controller控制器的实例化
资源加载器的根结尾,Result filter
Exception Filter
Exception Filter用来捕获异常。
创建认证的Filter
前面在家一个Ctm
创建Exception的Filter
实现接口,并加断点。
创建资源管理的Filter:CtmResourceFilterAttribute
加上断点
在HomeController里面把这几个Filter都加上
来看下执行的顺序
先到了认证的Filter
然后进入Resource
进入了ActionFilter
到了action里面
action的Executed
resource的Executed
走完。
这里之前加过action的Filter
会发现一个问题,从头到尾没有走Exception的Filter。它是用来捕获异常的
ExceptionFilter在权限和资源的Filter的下面。那么在ExceptionFilter下面的内容我们都可以捕获。上面的权限认证和资源的Filter可能捕获不到。
下面来验证我们上面的猜想。
手动的在action里面抛出一个异常。
测试下。
顺序还是先走的权限。
直到走到action里面,手动的抛出异常的代码了
异常出现了
再往下走
异常放到ActionFilter里面。
逐步的走到达异常的地方
发生异常
发生错误后,再往下走
到了ExceptionFilter
异常放在ResourceFilter
再来测试
显示认证的
发生错误
发生错误后,再往下走
直接跳到页面上了。因为Resource加载时间优于Exception。ExceptionFilter还没有加载呢,所以肯定是捕获不到的。
异常放在权限里面
异常放在Resource的Executed里面
报错了继续往下走
也是捕获不到。
比喻成一个面包。上下两层,手拿着捏面包,只有中间的才会漏出来,被异常捕获。虽然是上下两层,但是它是一个递归。Resource整体还是在Exception之前执行。
继续-演示winForm里面的aop
dotnetFramework的aop的形式
之前创建的AopDemo
这里启动 Form1
添加一个窗体
在Form1的窗体上,加一个按钮上去。然后双击写代码
添加一个文件夹Filters
添加一个类。
静态类。如果我们要给他增加一个特性
继承Attribute
这个aop就是在加载窗体的时候改变窗体的Text的值。
这里要对传入的对象进行查找
获取Form的Type
type是否包含FormFilterAttribute
true表示是否查找它的派生类。 这就是我们判断这个类上面有没有我们需要的FormFilter的Attribute
获取它的Attribute
前面需要强制转换成(FormFilterAttribute)
attribute里面有个Executing方法,把form传进去。
这块代码就可以从我们的Form的类里面获取Filter,并且调用Filter里面的数据。
没个调用form表单的地方替换掉。
form1的类上面加上attribute
需要传个参数。
启动测试
这里加个断点
运行后,进入到了这里
继续往下走。这样我们的表头就改变了。
扩展几个方法。
直接调用showWithAop传入当前的form2
方法改成showDialogWithAop
点击按钮
进入到了这里
往下走,调用了Form2
判断form的name不是form1就Dispose不展示,
再来新建一个窗体
新建叫做form3
启动测试,报错
这里加个断点
首先进来的是form1
Name是Form
我们要获取的是它对象的名称
改成大写的Form1
再来测试,还是报错
这里改成不等于
点击
走到了这里
上面的写法就是正常的dotnetFramework的aop的Filter反编译过来就是这么个展现形式
和现在dotnetCore的aop比起来比较low
讲解
先去找存不存在继承的接口的方法,如果找到了继承接口的方法,这个时候就从我的这个类上面找到AttributeFilter。那么就开始读取Filter并调用Filter里面的Executing方法。
然后把这个方法写到我要显示Control的委托的上面。
让它执行我这个control或者执行action的时候,先执行我们的aop的method
传进去的是一个control和一个上下文。我们可以根据上下文对控制器或者action进行判断,判断是否符合我们的规范或者权限。没有权限就跳转到无权限的页面。
打断点来看下顺序
这里再加个断点
启动测试
启动先进这里
往里走
逐过程,到了这里
在这里加个断点
重新启动程序。
这里再加个断点
然后就直接跳到这里了,RunApp
获取Form1的type类型,这里是反射。
看下这个类上,存不存在一个叫做FormFilterAttribute的特性。
存在就往下走了
获取自定义的特性。FormFilterAttribute是我们自己写的,也就是我们自定义的特性。
获取到这个特性之后,需要强制转换为FormFilterAttribute
因为我们的FOrmFilterAttribute继承自我们的Attribute
那么就可以获取里面的Executing方法。
然后就进入我们的Execuiting方法。
最终展现出来title被替换了。
当点击button1
触发了事件
我们当前是form2
回到WebApiDemo
F12进入IResourceFilter
接口里面有两个没有实现的方法
IFilterMetadata作为标记,还作为一个集合去使用。
我们后台这么多的Filter都存放在哪呢?他是存在IFilterMetaData的数组里面,
它可以作为一个容器去使用,把我们所有的Filter全部获取到,放到IFilterMetaData这样的一个数组里面。作为一个集合去使用,作为一个容器去使用。
只要继承了IFilterMetaData它必然就是一个过滤器。在这里它是作为一个标记去使用的。
在aop filter框架里面,它又作为集合去使用,所以只要是过滤器,它都要继承IFilterMetadata。
再次回到winFormDemo
这里先都注释掉
先来做几个Filter
命名空间加上Core把RunWithAop移到Core的文件夹下。
CtmActionFilterAttribute也移动到Filters的文件夹下。
加上命名空间
在Core下面创建接口
再来创建一个IResourceFilter
再来创建IFilterMatedata
接口内什么不写,作为标记和容器使用
IActionFilter继承IFilterMatedata
IResourceMatedata也继承IFilterMatedata
接口内创建两个方法
内也是加俩方法,和dotnetcore里面的filter方法很类似。
那么我们的CtmActionFilterAttribute就继承Attribute和IActionFilter
然后实现IActionFilter内的接口方法
再来添加一个CtxResourceAttribute
继承这俩并实现接口。
这样我们两个AOP就搞定了。和webApiDemo里面的AOP是一样的
准备写核心代码
上面就是准备工作做好了,下面开始写核心的代码了。
添加类FilterInvoke。在这里实现所有核心的代码。
首先来确认下流程大概是什么样的
下面是要执行的流程。如果读过源码的就知道它是用switch的语句来执行顺序的走向。
新建枚举,理想中有这四个环节就够了
下一步通过构造方法传入我们所必要的数据
凡是用到Filter特性,必然用到反射,反射根据什么获取到特性呢?就是跟我们的标记位。
说白了就是凡是有这个IFilterMateData接口的都是Filter,反射的时候会根据这个标志位来判断。标志位既是作为查找Filter的使用,也是作为存储标志位的使用。即作为容器也作为标记。