Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能
Autofac 结合 Castle DynamicProxy2 功能
Autofac 不仅作为轻量级高效的 IoC 容器,而且还能很好的与 Castle.DynamicProxy2 结合起来,实现 AOP 功能。
首先,我们需要定义拦截器,简单的定义可实现 Castle.DynamicProxy.IInterceptor 接口即可。
添加拦截器
定义好了拦截器后,如何应用到相关对象呢?有两种方式:
1)使用 Autofac.Extras.DynamicProxy2.InterceptAttribute 特性将拦截器添加到相关的类或接口上;
2)使用 ContainerBuilder 的 InterceptedBy() 方法在注册对象的同时添加拦截器。
如何启用拦截器呢?我们只需要在 IoC 注册启用即可。启用拦截器有三种方式,其中针对 WCF 比较特别,下面来具体分析这几种方式的应用场景:
基于接口的拦截器
在注册对象的同时启用 EnableInterfaceInterceptors() 方法。
使用接口的拦截器,在使用特性 [Attribute] 注册时,注册拦截器可注册到接口(Interface)上或其实现类(Implement)上。使用注册到接口上方式,所有的实现类都能应用到拦截器。
对于以接口方式的注入,Autofac Interceptor 要求类的方法为 public 或 virtual 即可。
示例代码:
var builder = new ContainerBuilder();
builder.RegisterType<SomeType>()
.As<ISomeInterface>()
.EnableInterfaceInterceptors();
builder.Register(c => new CallLogger(Console.Out));
var container = builder.Build();
var willBeIntercepted = container.Resolve<ISomeInterface>();
于类的拦截器
在注册对象的同时启用 EnableClassInterceptors() 方法。
对于以类方式的注入,Autofac Interceptor 要求类的方法为必须为 virtual 方法。
值得注意的是:对于 子类,重写(override)父类的虚方法时,能应用到拦截器。父类可在 IoC 中注册也可不需要注册,但子类必须在 IoC 中注册(对于类的拦截器,类都必须要注册,当然,拦截器也必须要注册)。
示例代码:
var builder = new ContainerBuilder(); builder.RegisterType<First>().EnableClassInterceptors(); builder.Register(c => new CallLogger(Console.Out));
基于 WCF 的拦截器
WCF 是一种特殊情况。虽然 WCF Proxy 的服务对象也是一种接口,但是使用 EnableInterfaceInterceptors 不会起作用,因为 .NET 实际上是使用了 类似于接口行为的 System.Runtime.Remoting.TransparentProxy 。因此需要这里需要使用 InterceptTransparentProxy() 方法。
示例代码:
var cb = new ContainerBuilder();
cb.RegisterType<TestServiceInterceptor>();
cb.Register(c => CreateChannelFactory()).SingleInstance();
cb.Register(c => c.Resolve<ChannelFactory<ITestService>>().CreateChannel())
.InterceptTransparentProxy(typeof(IClientChannel))
.InterceptedBy(typeof(TestServiceInterceptor))
.UseWcfSafeRelease();
实战一下
先看看基于接口的拦截器:
我们先定义一个借口,名为 ICalculater:
using Autofac.Extras.DynamicProxy2;
namespace AOP.Interceptors
{
//[Intercept(typeof(CalculaterInterceptor))]
public interface ICalculater
{
int Add(int x, int y);
int Sub(int x, int y);
}
}
然后定义该接口的实现类 Calculater:
using Autofac.Extras.DynamicProxy2;
namespace AOP.Interceptors
{
//[Intercept(typeof(CalculaterInterceptor))]
public class Calculater : ICalculater
{
public int Add(int x, int y)
{
return x + y;
}
public int Sub(int x, int y)
{
return x - y;
}
}
}
接下来,我们来定义拦截器。这里我们定义了两个连接器,通过这两个拦截器,我们将能很清晰的看到拦截器是如何工作的。
定义第一个拦截器 CalculaterInterceptor :
using System;
using Castle.DynamicProxy;
namespace AOP.Interceptors
{
public class CalculaterInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// 在下个拦截器或目前方法处理之前处理
var args = invocation.Arguments;
Console.WriteLine($"Before: x={args[0]}, y={args[1]}");
Console.WriteLine($"Before: Method={invocation.Method.Name}");
invocation.SetArgumentValue(0, 5);
// handle
invocation.Proceed(); // 调用下一个拦截器,直到最终的目标方法。
// Post
Console.WriteLine($"After: TargetType={invocation.TargetType}");
Console.WriteLine($"After: ReturnValue={invocation.ReturnValue}");
invocation.ReturnValue = (int)invocation.ReturnValue - 2;
}
}
}
定义第二个拦截器 CalculaterInterceptor2 :
using System;
using Castle.DynamicProxy;
namespace AOP.Interceptors
{
public class CalculaterInterceptor2 : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var args = invocation.Arguments;
Console.WriteLine($"Before2: x={args[0]}, y={args[1]}");
Console.WriteLine($"Before2: Method={invocation.Method.Name}");
invocation.Proceed();
Console.WriteLine($"After2: TargetType={invocation.TargetType}");
Console.WriteLine($"After2: ReturnValue={invocation.ReturnValue}");
invocation.ReturnValue = (int)invocation.ReturnValue - 1; // 将结果值减去 2
}
}
}
在 控制台 Main 函数输入我们的结果:
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Calculater>()
.As<ICalculater>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2)); // 这里定义了两个拦截器,注意它们的顺序
builder.RegisterType<CalculaterInterceptor>(); // 注册拦截器
builder.RegisterType<CalculaterInterceptor2>(); // 注册拦截器2
var ioc = builder.Build();
var calculater = ioc.Resolve<ICalculater>();
var addResult = calculater.Add(2, 3);
Console.WriteLine($"add result: {addResult}");
Console.WriteLine("-------------------");
Console.ReadLine();
}
我们看看输出结果:
这里我们可以看出,执行顺序为 CalculaterInterceptor --> CalculaterInterceptor2 --> Target Method --> CalculaterInterceptor2 --> CalculaterInterceptor。拦截器中 invocation.Proceed() 方法用于调用下一个拦截器(若存在),直到最终的目标方法(Target Method)。不过 invocation.Proceed() 并不是一定要调用的,例如,对于有返回值的目标方法,我们在拦截器中设置 invocation.ReturnValue 值就可正确执行,这样便不会执行目标方法。在有些场景中,如身份验证、缓存读取等还是特别有用的。
当然,在 Main() 方法中 Ioc 注册 Caliculater 类型时我们注册了两个拦截器,".InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2))"。我们也可以直接在 Calculater 类型 或 ICalculater 接口上以特性的形式注册,如上面代码中注释掉的那部分。若是既有在类型上注册,也有在 Autofac 的 Builder 中注册,那么这个拦截器会重复执行。
基于类的拦截器:
我们定义两个类 Flight 和其 子类 FlightOfSH:
public class Flight
{
public virtual void Fly(DateTime time)
{
Console.WriteLine($"Flight: {time}");
}
}
public class FlightOfSH : Flight
{
public override void Fly(DateTime time)
{
Console.WriteLine($"FlightOfSH: Fly={time}");
}
public void Arrive(DateTime time)
{
Console.WriteLine($"FlightOfSH: Arrive={time}");
}
}
这两个类的拦截器:
internal class FlightInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("Before Fly");
invocation.Proceed();
Console.WriteLine("After Fly");
}
}
在 Main 函数中定义代码:
var builder = new ContainerBuilder();
builder.RegisterType<Flight>()
.EnableClassInterceptors().InterceptedBy(typeof(FlightInterceptor));
builder.RegisterType<FlightOfSH>()
.EnableClassInterceptors().InterceptedBy(typeof(FlightInterceptor));
builder.RegisterType<FlightInterceptor>();
var ioc = builder.Build();
var flight = ioc.Resolve<Flight>();
flight.Fly(DateTime.Now);
var flightOfSH = ioc.Resolve<FlightOfSH>();
flightOfSH.Fly(DateTime.Now);
flightOfSH.Arrive(DateTime.Now);
我们看看输出结果:
从输出结果中可以发现一个有趣的现在, 子类 FlightOfSH 重写了 Flight 的 Fly 方法,却也调用才拦截器。Arrive() 方法因为是非虚方法,所有拦截器不会在该方法中调用。
当然,我们这里都是直接在 Autofac 的 Ioc 注册类型时设定的,也可以同上面一样使用 InterceptAttribute 特性来注入。
对于基于 WCF 的拦截器,大家可以自己试验下。
总结
这里简单的介绍了 Autofac 与 Castle 动态代理功能结合来实现 AOP 功能,当然,Castle 本身也是个很强大的开源框架,也有很强大的 IoC 功能,不过我还是比较喜欢 Autofac 的 IoC 功能。
相关文章:
使用 Autofac 进行依赖注入
ASP.NET Core依赖注入解读&使用Autofac替代实现
原文链接:http://www.cnblogs.com/god--love-you/p/5699632.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能相关推荐
- 基于 MongoDB 的 python 日志功能
本文首发于 Gevin的博客 原文链接:基于MongoDB的python日志功能 未经 Gevin 授权,禁止转载 基于MongoDB的python日志功能 why-log-to-mongodb 我几 ...
- python程序实例电话本-Python基于递归实现电话号码映射功能示例
本文实例讲述了Python基于递归实现电话号码映射功能.分享给大家供大家参考,具体如下: 问题 电话按键上面的每个数字都对应着几个字母,如果按下一个数字键代表输入一个字母,那么输入一个数字组成的字符串 ...
- 递归二分法php,PHP基于二分法实现数组查找功能示例【循环与递归算法】
本文实例讲述了PHP基于二分法实现数组查找功能.分享给大家供大家参考,具体如下: 二分法.分别使用while循环的方法和递归调用的方法. // 二分法的使用数组必须是有序的,或升序,或降序 $arr ...
- mysql sqlite 分页查询_php基于SQLite实现的分页功能示例
本文实例讲述了php基于SQLite实现的分页功能.分享给大家供大家参考,具体如下: 这里操作数据库文件使用的是前面文章<PHP基于PDO实现的SQLite操作类[包含增删改查及事务等操作]&g ...
- SAP UI5 应用开发教程之三十四 - SAP UI5 应用基于设备类型的页面适配功能(Device Adaptation)试读版
一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...
- php 调用日历控制,基于ThinkPHP实现的日历功能实例详解
本文实例讲述了基于ThinkPHP实现的日历功能.分享给大家供大家参考,具体如下: 开发环境介绍 最新,闲来没事,便开发了一款简单的日历,来统计工作情况.为了开发便捷,使用ThinkPHP架构.界面如 ...
- (29)基于FPGA实现看门狗功能(FPGA不积跬步101)
1 引言 微处理(ARM.单片机)在特殊的环境下,运行代码或程序会跑到非预期状态,也就是说系统可能会进入死循环,这种情况微处理器无法进行自我恢复,只能通过复位或者重启进行解决.看门狗就是解决这种情况 ...
- 基于FPGA实现PCIE IP功能仿真
基于FPGA实现PCIE IP功能仿真 1 开发工具 modelsim simulator或vivado simulator,本设计采用modelsim进行仿真. 2 参数配置
- python实现离线翻译_基于python实现百度翻译功能
运行环境: python 3.6.0 今天处于练习的目的,就用 python 写了一个百度翻译,是如何做到的呢,其实呢就是拿到接口,通过这个接口去访问,不过中间确实是出现了点问题,不过都解决掉了 先晾 ...
最新文章
- Linux下利用phpize安装php扩展
- mybatis mysql Druid_mybatis+Druid连接池的问题
- 数据院携手汽车工程系,女生节尽展清华大数据风采~
- Python GUI编程-了解相关技术[整理]
- Java调用.NET的WCF
- 优酷电视剧爬虫代码实现一:下载解析视频网站页面(3)补充知识点:htmlcleaner使用案例...
- select for update作用
- python库skimage 将针对灰度图像的滤波器用于RGB图像
- 某超级注入程序的驱动逆向
- 无法忘却的旋律:《荷东》、《猛士》各专辑的曲目列表
- 微信开发平台对接流程(Java版本)1
- 计算机用户账户限制,win7系统使用共享功能被提示用户账户限制怎么解决
- 融资融券的交易成本有哪些?
- STM32 DFU下载与 DFU生成工具
- 数据库面试考题一览(全面覆盖)
- 如何在 FlowUs、Notion 等笔记软件中进行时间管理?
- net start mysql:无法启动
- Nvidia Agx Xavier平台10Gb PCIE网卡速度限制为1Gb问题调试记录
- Android应用中实现系统“分享”接口
- Word及Excel文档的Python脚本处理