使用Castle DynamicProxy (AOP)

在本文中,我將引導您瞭解.NET環境中的面向方面編程(AOP)概念,以及如何使用Castle DynamicProxy建立和附加方面在咱們開始以前,讓我快速介紹AOP和  IoC若是您已經熟悉這些概念,則能夠徹底跳過本節。編程

什麼是AOP?

方面 - 面向對象編程  ( AOP)是一種 編程 範式,旨在經過容許的橫切關注分離,以增長模塊性。 一個方面是一般分散在方法,類和對象層次結構中的常見功能。看起來像它的行爲具備結構,可是找不到使用傳統的面向對象技術來表達它的方法。框架

一個很好的例子就是日誌記錄,我將在本文中詳細討論。一般,您在代碼庫中寫入信息豐富的日誌,但日誌記錄是您的類或對象模型真的不該該關心的,由於它不表明域對象。spa

使用AOP方法,咱們能夠建立這些交叉關注的方面,並使用多種技術將它們集中在域對象上。IL代碼編織和截取是普遍使用的方法。在本文中,我將介紹使用Castel Windsor框架動態建立和應用方面的過程。代理

控制反轉(IoC)/依賴注入(DI)容器

IoC容器是一種在須要時自動建立和注入依賴項的框架。DI容器幫助咱們以簡單和更有效的方式管理應用程序中的依賴關係。日誌

大多數主流DI(依賴注入)容器都內置支持攔截。使用這種方法,您能夠在運行時調用和更改域對象的行爲來攔截該方法。咱們將利用此功能將方面附加到咱們的域對象。個人DI框架選擇是城堡溫莎,其DynamicProxy是應用方面的流行方式之一。code

Code Project中有不少很好的文章和不一樣的博客,能夠爲您提供有關此(IoC)主題的更多詳細信息。關於IoC的詳細討論超出了本文的範圍。 orm

攔截使用Castle DynamicProxy

Castle DynamicProxy是一個用於在運行時生成.NET代理的庫。它容許您動態地更改和擴展業務對象的行爲。這使得您的域模型更加可維護,由於交叉關切純粹與核心域模型脫鉤。若是爲任何組件指定攔截器,Castle將自動建立代理。您使用攔截器將代理注入行爲。對象

你可能想知道這整個事情在內部如何工做。每當調用者請求業務對象(具體類)時,IoC容器將在DynamicProxy的幫助下解析並將其包裝在包含指定攔截器的代理對象中。容器而後將代理的對象返回給調用者。來電者而後直接與代理人進行交互。代理攔截對業務對象的每一個方法調用,並讓請求流過攔截器管道。blog

 

下圖顯示了請求如何流入代理。您能夠看到請求在實際執行方法以前和以後經過全部攔截器。接口

在您的項目中設置Castle DynamicProxy的步驟

  • 從NuGet下載並安裝「Castle.Windsor」軟件包。
  • 實現IInterceptor接口。這是DynamicProxy將要使用的接口。
  • 實施IRegistration界面並註冊您的組件。註冊攔截器後跟業務組件。指定要與每一個業務組件一塊兒使用的攔截器。
  • 建立Windsor容器(IWindsorContainer)的靜態實例,使用組件註冊信息進行初始化。

這幾乎是配置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實現此解決方案。 

相關文章
相關標籤/搜索