在本文中,我將引導您瞭解.NET環境中的面向方面編程(AOP)概念,以及如何使用Castle DynamicProxy建立和附加方面。在咱們開始以前,讓我快速介紹AOP和 IoC。若是您已經熟悉這些概念,則能夠徹底跳過本節。編程
方面 - 面向對象編程 ( AOP)是一種 編程 範式,旨在經過容許的橫切關注分離,以增長模塊性。 一個方面是一般分散在方法,類和對象層次結構中的常見功能。看起來像它的行爲具備結構,可是找不到使用傳統的面向對象技術來表達它的方法。框架
一個很好的例子就是日誌記錄,我將在本文中詳細討論。一般,您在代碼庫中寫入信息豐富的日誌,但日誌記錄是您的類或對象模型真的不該該關心的,由於它不表明域對象。spa
使用AOP方法,咱們能夠建立這些交叉關注的方面,並使用多種技術將它們集中在域對象上。IL代碼編織和截取是普遍使用的方法。在本文中,我將介紹使用Castel Windsor框架動態建立和應用方面的過程。代理
IoC容器是一種在須要時自動建立和注入依賴項的框架。DI容器幫助咱們以簡單和更有效的方式管理應用程序中的依賴關係。日誌
大多數主流DI(依賴注入)容器都內置支持攔截。使用這種方法,您能夠在運行時調用和更改域對象的行爲來攔截該方法。咱們將利用此功能將方面附加到咱們的域對象。個人DI框架選擇是城堡溫莎,其DynamicProxy是應用方面的流行方式之一。code
Code Project中有不少很好的文章和不一樣的博客,能夠爲您提供有關此(IoC)主題的更多詳細信息。關於IoC的詳細討論超出了本文的範圍。 orm
Castle DynamicProxy是一個用於在運行時生成.NET代理的庫。它容許您動態地更改和擴展業務對象的行爲。這使得您的域模型更加可維護,由於交叉關切純粹與核心域模型脫鉤。若是爲任何組件指定攔截器,Castle將自動建立代理。您使用攔截器將代理注入行爲。對象
你可能想知道這整個事情在內部如何工做。每當調用者請求業務對象(具體類)時,IoC容器將在DynamicProxy的幫助下解析並將其包裝在包含指定攔截器的代理對象中。容器而後將代理的對象返回給調用者。來電者而後直接與代理人進行交互。代理攔截對業務對象的每一個方法調用,並讓請求流過攔截器管道。blog
下圖顯示了請求如何流入代理。您能夠看到請求在實際執行方法以前和以後經過全部攔截器。接口
這幾乎是配置Castle DynamicProxy所須要的!
讓咱們從咱們的示例應用程序開始。此應用程序包含一個業務對象「火箭」,咱們使用控制檯應用程序啓動。
接口包含一個稱爲「啓動」的單一方法簽名。
public interface IRocket { void Launch(int delaySeconds); }
容許經過實現惟一須要的方法「啓動」實現接口。
public class Rocket: IRocket { public string Name { get; set; } public string Model { get; set; } public void Launch(int delaySeconds) { Console.WriteLine(string.Format("Launching rocket in {0} seconds",delaySeconds)); Thread.Sleep(1000 * delaySeconds); Console.WriteLine("Congratulations! You have successfully launched the rocket"); } }
時間來建立咱們的第一個攔截器。咱們能夠經過實現IInterceptor接口來實現。這是DynamicProxy將要使用的接口。
以下所示,咱們正在登陸方法條目,調用執行實際方法的invocation.Proceed()方法,登陸成功執行,登陸異常和退出登陸。咱們沒必要在其中編寫日誌記錄代碼咱們的業務模式了!咱們只須要將LoggingInterceptor附加到須要記錄的組件上。
public class LoggingInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { var methodName = invocation.Method.Name; try { Console.WriteLine(string.Format("Entered Method:{0}, Arguments: {1}", methodName, string.Join(",", invocation.Arguments))); invocation.Proceed(); Console.WriteLine(string.Format("Sucessfully executed method:{0}", methodName)); } catch (Exception e) { Console.WriteLine(string.Format("Method:{0}, Exception:{1}", methodName, e.Message)); throw; } finally { Console.WriteLine(string.Format("Exiting Method:{0}", methodName)); } }
DynamicProxy公開的IInvocation對象很是有用。它能夠訪問當前的MethodInfo,Arguments,ReturnValue和許多其餘細節,以下所示。
public interface IInvocation { object[] Arguments { get; } Type[] GenericArguments { get; } object InvocationTarget { get; } MethodInfo Method { get; } MethodInfo MethodInvocationTarget { get; } object Proxy { get; } object ReturnValue { get; set; } Type TargetType { get; } object GetArgumentValue(int index); MethodInfo GetConcreteMethod(); MethodInfo GetConcreteMethodInvocationTarget(); void Proceed(); void SetArgumentValue(int index, object value); }
實施IRegistration界面並註冊您的組件。註冊攔截器後跟業務組件。指定要與每一個業務組件一塊兒使用的攔截器。您可能已經注意到,LoggingInterceptor附加到咱們惟一的業務組件Rocket
public class ComponentRegistration : IRegistration { public void Register(IKernelInternal kernel) { kernel.Register( Component.For<LoggingInterceptor>() .ImplementedBy<LoggingInterceptor>()); kernel.Register( Component.For<IRocket>() .ImplementedBy<Rocket>() .Interceptors(InterceptorReference.ForType<LoggingInterceptor>()).Anywhere); } }
建立Windsor容器(IWindsorContainer)的靜態實例,使用組件註冊信息進行初始化。
public class DependencyResolver { private static IWindsorContainer _container; //Initialize the container public static void Initialize() { _container = new WindsorContainer(); _container.Register(new ComponentRegistration()); } //Resolve types public static T For<T>() { return _container.Resolve<T>(); } }
用於運行咱們的代碼的微型控制檯應用程序。
internal class Program { public static void Main(string[] args) { //Initialize the dependency resolver DependencyResolver.Initialize(); //resolve the type:Rocket var rocket = DependencyResolver.For<IRocket>(); //method call try { rocket.Launch(5); } catch (Exception ex) { } System.Console.ReadKey(); } }
讓咱們看看控制檯輸出。正如你所指望的,咱們的LoggingInterceptor攔截了方法調用和記錄的方法條目並自動退出。感謝DynamicProxy!
這是一篇介紹性文章,讓初學者和中級開發人員使用Castle Windsor DynamicProxy瞭解AOP的基本概念。在將來的日子裏,我將繼續更新本文,並展現如何在Web Api項目中使用Log4net和DynamicProxy實現此解決方案。