Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能
来源:互联网 发布:石家庄盛光网络 编辑:程序博客网 时间:2024/06/10 10:07
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 功能
- Autofac+Castle实现AOP事务
- IoC容器Autofac(3) - 理解Autofac原理,我实现的部分Autofac功能(附源码)
- 基于Castle+IBatisNet+Castle.MVC的ASP.NET构架
- 基于Castle+IBatisNet+Castle.MVC的ASP.NET构架
- [AOP系列]Autofac+Castle实现AOP事务
- Ioc容器-Autofac 之四-依赖注入框架Autofac的简单使用
- okhttp的interceptor拦截器功能
- 使用CASTLE的注意事项之二:级联
- IOC 之AutoFac攻略
- IOC之Autofac
- 基于.Net(Castle+nhibernate)的松散式工作流引擎(一)
- 基于Java Bouncy Castle的PGP加密解密示例
- 基于Java Bouncy Castle的PGP加密解密示例
- autofac的简单使用
- Autofac的使用
- Autofac 的简单配置
- AutoFac 的使用
- 2016年10月20日 .NET Core 1.0.2 更新
- [ASP.NET Core] Static File Middleware
- 微软市值今天涨了 250 亿,这家离我们越来越远的公司,为什么生意反倒越来越好了?
- 使用StyleCop 进行代码评审
- ASP.NET Core MVC TagHelper实践HighchartsNET快速图表控件
- Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能
- 微服务架构之外的选择——基于服务架构
- [ASP.NET Core] Middleware
- Visual Studio“15”进一步改善性能和易用性
- ASP.NET Core 性能对比评测(ASP.NET,Python,Java,NodeJS)
- 微软开源P语言,实现安全的异步事件驱动编程
- 在Linux和Windows的Docker容器中运行ASP.NET Core
- 在.NET Core中使用MEF
- 编程语言的发展趋势及未来方向(4):动态语言