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 功能相关推荐

  1. 基于 MongoDB 的 python 日志功能

    本文首发于 Gevin的博客 原文链接:基于MongoDB的python日志功能 未经 Gevin 授权,禁止转载 基于MongoDB的python日志功能 why-log-to-mongodb 我几 ...

  2. python程序实例电话本-Python基于递归实现电话号码映射功能示例

    本文实例讲述了Python基于递归实现电话号码映射功能.分享给大家供大家参考,具体如下: 问题 电话按键上面的每个数字都对应着几个字母,如果按下一个数字键代表输入一个字母,那么输入一个数字组成的字符串 ...

  3. 递归二分法php,PHP基于二分法实现数组查找功能示例【循环与递归算法】

    本文实例讲述了PHP基于二分法实现数组查找功能.分享给大家供大家参考,具体如下: 二分法.分别使用while循环的方法和递归调用的方法. // 二分法的使用数组必须是有序的,或升序,或降序 $arr ...

  4. mysql sqlite 分页查询_php基于SQLite实现的分页功能示例

    本文实例讲述了php基于SQLite实现的分页功能.分享给大家供大家参考,具体如下: 这里操作数据库文件使用的是前面文章<PHP基于PDO实现的SQLite操作类[包含增删改查及事务等操作]&g ...

  5. SAP UI5 应用开发教程之三十四 - SAP UI5 应用基于设备类型的页面适配功能(Device Adaptation)试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  6. php 调用日历控制,基于ThinkPHP实现的日历功能实例详解

    本文实例讲述了基于ThinkPHP实现的日历功能.分享给大家供大家参考,具体如下: 开发环境介绍 最新,闲来没事,便开发了一款简单的日历,来统计工作情况.为了开发便捷,使用ThinkPHP架构.界面如 ...

  7. (29)基于FPGA实现看门狗功能(FPGA不积跬步101)

    1 引言  微处理(ARM.单片机)在特殊的环境下,运行代码或程序会跑到非预期状态,也就是说系统可能会进入死循环,这种情况微处理器无法进行自我恢复,只能通过复位或者重启进行解决.看门狗就是解决这种情况 ...

  8. 基于FPGA实现PCIE IP功能仿真

    基于FPGA实现PCIE IP功能仿真 1 开发工具 modelsim simulator或vivado simulator,本设计采用modelsim进行仿真. 2 参数配置

  9. python实现离线翻译_基于python实现百度翻译功能

    运行环境: python 3.6.0 今天处于练习的目的,就用 python 写了一个百度翻译,是如何做到的呢,其实呢就是拿到接口,通过这个接口去访问,不过中间确实是出现了点问题,不过都解决掉了 先晾 ...

最新文章

  1. Linux下利用phpize安装php扩展
  2. mybatis mysql Druid_mybatis+Druid连接池的问题
  3. 数据院携手汽车工程系,女生节尽展清华大数据风采~
  4. Python GUI编程-了解相关技术[整理]
  5. Java调用.NET的WCF
  6. 优酷电视剧爬虫代码实现一:下载解析视频网站页面(3)补充知识点:htmlcleaner使用案例...
  7. select for update作用
  8. python库skimage 将针对灰度图像的滤波器用于RGB图像
  9. 某超级注入程序的驱动逆向
  10. 无法忘却的旋律:《荷东》、《猛士》各专辑的曲目列表
  11. 微信开发平台对接流程(Java版本)1
  12. 计算机用户账户限制,win7系统使用共享功能被提示用户账户限制怎么解决
  13. 融资融券的交易成本有哪些?
  14. STM32 DFU下载与 DFU生成工具
  15. 数据库面试考题一览(全面覆盖)
  16. 如何在 FlowUs、Notion 等笔记软件中进行时间管理?
  17. net start mysql:无法启动
  18. Nvidia Agx Xavier平台10Gb PCIE网卡速度限制为1Gb问题调试记录
  19. Android应用中实现系统“分享”接口
  20. Word及Excel文档的Python脚本处理

热门文章

  1. MongoDB 权限认证
  2. php 利用http上传协议(表单提交上传图片 )
  3. Emoji:搜索将与您找到表情符号背后的故事
  4. Kubernetes:标签、选择器、注解、容忍度、亲和性
  5. .NET 程序测试 Java 项目 log4j2 是否存在远程代码执行漏洞
  6. .NET 6 预览版 7 Released
  7. C# 爬虫:疫情实时信息图
  8. ML.NET Cookbook:(4)如何调试实验或预览管道?
  9. 使用 Tye 辅助开发 k8s 应用竟如此简单(一)
  10. 「译」 用 Blazor WebAssembly 实现微前端