使用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实现此解决方案。 

相关文章
相关标签/搜索