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

  • 相关阅读:
    Android开发学习一:环境搭建
    Python Challenge
    Python Challenge
    Python Challenge
    Centos中的mysql安装以及配置
    linux查询日志内容命令
    搭建elasticsearch过程中遇到的问题
    启动kafka后闪退
    zookeeper环境搭建
    nginx安装
  • 原文地址:https://www.cnblogs.com/chunjin/p/6801335.html
Copyright © 2011-2022 走看看