Unity框架的拦截注入
发表于2018-11-12
AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。下面要给大家介绍Unity框架的拦截注入。
Unity拦截注入可以在运行时有效捕获对象方法调用,并给对象附加上额外的功能。很适用于改变某单个实例的行为,而不是整个类的行为,这如同装饰模式。装饰模式是什么?
namespace ConsoleUnityDemo.Decrotor { public interface IWindow { void Show(); } public class ConcreteWindow : IWindow { public void Show() { Console.WriteLine("Show Window"); } } public class Program { static void Main(string[] args) { IWindow model = new ConcreteWindow(); ShowWindow(model); } static void ShowWindow(IWindow model) { model.Show(); } } }
以上代码中Main中调用了IWindow的Show方法。IWindow的实例可能做为别的组件的一个契约,一般情况下不允许修改,但业务要又要求加上新功能,这种情况下用Decorate Pattern改修改代码。在没有改变ConcreteWindow类的情况下,给ConcreteWindow实例的Show()方法添加了一个新行为。以下代码DecoratorWindow即为ConcreateWindow的实例的Show方法添加了一个新行为。
namespace ConsoleUnityDemo.Decorator { public interface IWindow { void Show(); } public class ConcreteWindow : IWindow { public void Show() { Console.WriteLine("Show Window"); } } public class DecoratorWindow : IWindow { IWindow instance; public DecoratorWindow(IWindow model) { instance = model; } public void Show() { instance.Show(); Console.WriteLine("Add a behavior"); } } public class Program { static void Main(string[] args) { IWindow model = new ConcreteWindow(); IWindow decoratorWindow = new DecoratorWindow(model); ShowWindow(decoratorWindow); } static void ShowWindow(IWindow model) { model.Show(); } } }
Unity中的Type Interception
类型截取不是代理服务器使用派生的类。实例截取的工程通过创建目标对象的代理。类型拦截、 更密切地类似于面向方面编程 (AOP) 技术常见的基于 Java 的系统。类型拦截避免了通过动态地从原始类派生新类并插入对的行为构成了管道的调用使用一个代理对象的性能损耗。下面的示意图显示类型截取的基本过程
Demo
1. MyClassForProxyInterception是将要被拦截的一个类,这个类必需从MarshalByRefObject类继承。
public class MyClassForProxyInterception : MarshalByRefObject { public string Width { get; set; } public void Method() { Console.WriteLine("invoke:MyClassForProxyInterception.Method"); } }
2. 自定义一个拦截捕获行为MyInterceptionBehavior,这个类必需从Microsoft.Practices.Unity.InterceptionExtension.IInterceptionBehavior接口继承。在Invoke中添加自定义方法。
public class MyInterceptionBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("The method of target object has intercepted!"); return getNext()(input, getNext); } public bool WillExecute { get { return true; } } }
3. 配置
在register节点中向MyClassForProxyInterception类添加拦截对向interceptor,interceptor类型为TransparentProxyInterceptor,再用MyInterceptionBehavior来处理拦截行为。
Unity默认提供了3种interceptor,分别为:VirtualMethodInterceptor、interfaceInterceptor、TransparentProxyInterceptor,其中TransparentProxyInterceptor会捕获对象的所有行为,当然不包括private和protected的方法等属性
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unityInterception" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unityInterception> <alias alias="MyClass" type="ConsoleUnityDemo.MyClassForProxyInterception, ConsoleUnityDemo" /> <alias alias="MyInterceptionBehavior" type="ConsoleUnityDemo.MyInterceptionBehavior, ConsoleUnityDemo" /> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <container name="MyInterception"> <extension type="Interception" /> <register type="MyClass"> <!-- Other children, like constructor or property --> <interceptor type="TransparentProxyInterceptor" /> <interceptionBehavior name="MyBehavior" type="MyInterceptionBehavior" /> <policyInjection /> </register> </container> </unityInterception> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
最后验证代码
public class InterceptionDemo { #region Interception Injection static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unityInterception"); IUnityContainer container = new UnityContainer(); unitySection.Configure(container, "MyInterception"); var obj = container.Resolve<MyClassForProxyInterception>(); obj.Method(); obj.Width = "100px"; Console.ReadKey(); } #endregion }
运行代码,MyInterceptionBehavior被调用2次,一次是Method方法调用,一次是Width属性被修改。
完整代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity.InterceptionExtension; using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using System.Configuration; using System.Reflection; using System.ComponentModel; namespace ConsoleUnityDemo { public class MyClassForProxyInterception : MarshalByRefObject { public string Width { get; set; } public void Method() { Console.WriteLine("invoke:MyClassForProxyInterception.Method"); } } public class MyInterceptionBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return new[] { typeof(INotifyPropertyChanged) }; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("The method of target object has intercepted!"); return getNext()(input, getNext); } public bool WillExecute { get { return true; } } } public class InterceptionDemo { #region Interception Injection static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unityInterception"); IUnityContainer container = new UnityContainer(); unitySection.Configure(container, "MyInterception"); var obj = container.Resolve<MyClassForProxyInterception>(); obj.Method(); obj.Width = "100px"; Console.ReadKey(); } #endregion } }