Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能
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>();
var builder = new ContainerBuilder(); builder.RegisterType<First>() .EnableClassInterceptors(); builder.Register(c => new CallLogger(Console.Out));
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"); } }
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);