zoukankan      html  css  js  c++  java
  • 使用Castle DynamicProxy (AOP)

    在本文中,我将引导您了解.NET环境中的面向方面编程(AOP)概念,以及如何使用Castle DynamicProxy创建和附加方面在我们开始之前,让我快速介绍AOP和  IoC如果您已经熟悉这些概念,则可以完全跳过本节。

    什么是AOP?

    方面 - 面向对象编程  ( AOP)是一种 编程 范式,旨在通过允许的横切关注分离,以增加模块性。 一个方面是通常分散在方法,类和对象层次结构中的常见功能。看起来像它的行为具有结构,但是找不到使用传统的面向对象技术来表达它的方法。

    一个很好的例子就是日志记录,我将在本文中详细讨论。通常,您在代码库中写入信息丰富的日志,但日志记录是您的类或对象模型真的不应该关心的,因为它不代表域对象。

    使用AOP方法,我们可以创建这些交叉关注的方面,并使用多种技术将它们集中在域对象上。IL代码编织和截取是广泛使用的方法。在本文中,我将介绍使用Castel Windsor框架动态创建和应用方面的过程。

    控制反转(IoC)/依赖注入(DI)容器

    IoC容器是一种在需要时自动创建和注入依赖项的框架。DI容器帮助我们以简单和更有效的方式管理应用程序中的依赖关系。

    大多数主流DI(依赖注入)容器都内置支持拦截。使用这种方法,您可以在运行时调用和更改域对象的行为来拦截该方法。我们将利用此功能将方面附加到我们的域对象。我的DI框架选择是城堡温莎,其DynamicProxy是应用方面的流行方式之一。

    Code Project中有很多很好的文章和不同的博客,可以为您提供有关此(IoC)主题的更多详细信息。关于IoC的详细讨论超出了本文的范围。 

    拦截使用Castle DynamicProxy

    Castle DynamicProxy是一个用于在运行时生成.NET代理的库。它允许您动态地更改和扩展业务对象的行为。这使得您的域模型更加可维护,因为交叉关切纯粹与核心域模型脱钩。如果为任何组件指定拦截器,Castle将自动创建代理。您使用拦截器将代理注入行为。

    你可能想知道这整个事情在内部如何工作。每当调用者请求业务对象(具体类)时,IoC容器将在DynamicProxy的帮助下解析并将其包装在包含指定拦截器的代理对象中。容器然后将代理的对象返回给调用者。来电者然后直接与代理人进行交互。代理拦截对业务对象的每个方法调用,并让请求流过拦截器管道。

     

    下图显示了请求如何流入代理。您可以看到请求在实际执行方法之前和之后通过所有拦截器。

    在您的项目中设置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实现此解决方案。 

  • 相关阅读:
    DPDK安装方法 17.12.13
    numa.h:No such file or directory 解决方法
    17秋 软件工程 第六次作业 Beta冲刺 Scrum3
    17秋 软件工程 第六次作业 Beta冲刺 总结博客
    17秋 软件工程 第六次作业 Beta冲刺 Scrum2
    Paper Reviews and Presentations
    17秋 软件工程 第六次作业 Beta冲刺 Scrum1
    17秋 软件工程 第六次作业 Beta冲刺
    error: could not create '/System/Library/Frameworks/Python.framework/Versions/2.7/share': Operation not permitted
    17秋 软件工程 个人作业 软件产品案例分析
  • 原文地址:https://www.cnblogs.com/chunjin/p/6801335.html
Copyright © 2011-2022 走看看