原文链接:Aspect Oriented Programming (AOP) in C# using CastleDynamicProxy

本文主要展示在C#中如何使用Castle DynamicProxy来解耦logging体系

简介

在这篇文章中,我将带你在.NET环境中实现Aspect-Oriented Programming (AOP) ,演示如何使用Castle DynamicProxy创建一个切面。在开始之前,我简单的介绍下AOP and IoC如果你已经熟悉这些概念,你可以直接跳过下面的步骤。

什么是AOP?

Aspect-oriented programming (AOP) 面向切面编程是一个编程范式,以允许增加模块化横切关注点的分离。An aspect (方面,AOP概念中的术语,为了不混淆,下文使用英文表示,不做中文翻译)是一种常见的功能,通常是分散在类和对象层次结构中的公用方法。这些行为看起来有结构,但使用传统的面向对象编程(OOP)无法找到一个方式来表达它。

aspect一个比较贴切的例子是本文中将要讨论的日志记录功能,通常你需要在代码中编写日志,但是日志功能通常并不属于领域对象的职责。

使用AOP方法,我们可以创建这些aspects的横切关注点,并使用多种技术将它们集中附加到领域对象。IL代码编织和拦截是广泛使用的方法。在本文中,我将带你使用Castel Windsor动态框架来处理aspects的创建和应用。

控制反转(Inversion of control=Ioc)/依赖注入容器(DI Container)

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

大多数的主流的DI(依赖注入)容器具有拦截的内置支持。这是一项高级技术,使用它可以拦截方法调用并改变在运行时期间的域对象的行为。我们将利用此功能附加aspects到我们的域对象。我选择的DI框架是Castle Windsor ,它的 DynamicProxy ,是比较流行的应用aspects的方法之一。

在CodeProject有很多很好的文章和博客提供了关于(IoC)主题更详细的资料。对IoC更大范围的详细讨论不在本文的范围内。

使用Castle DynamicProxy进行拦截

Castle DynamicProxy是一个在运行时生成.NET代理的库。 它允许你动态地更改和扩展业务对象的行为。因为横切关注点与核心领域模型的彻底解耦使得你的域模型更容易维护。如果为任何组件指定拦截,Castle 会自动创建代理。可以使用拦截器注入特定行为到代理中。

你可能会好奇这整件事的内部如何工作。每当调用方请求业务对象(具体类),IoC容器在DynamicProxy的帮助下,解析并将其包装在一个包含指定的拦截器的代理对象中。然后容器返回代理对象到调用方。然后,调用方直接与代理进行交互。 代理截取每个针对业务对象的方法调用,并让请求按照流程通过拦截器传递

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

在项目中使用 Castle DynamicProxy的步骤

· 使用Nuget下载和安装 ‘Castle.Windsor’  包.

· 实现 IInterceptor 接口. 这是要被 DynamicProxy的接口.

  • 实现IRegistration 接口并且注册组件. 注册拦截器其次是业务组件。指定每个业务组件要使用的拦截器。
  • 为Windsor创建静态实例容器(IWindsorContainer),用该组件注册信息初始化它。.

这几乎是Castle DynamicProxy需要的所有配置

开始编码

晴朗的一天在班加罗尔微风习习,这样的天气条件适合发射火箭!让我们开始我们的示例应用程序。 此应用程序包含业务对象'Rocket'我们使用一个控制台应用程序来模拟火箭的发射。

接口包含一个签名叫” Launch”的行为。

public interface IRocket

{

    void Launch(int delaySeconds);

}

然后我们来实现接口中的”Launch”方法。

public class Rocket : IRocket

{

    public string Name { get; set; }

    public string Model { get; set; }

 

    public void Launch(int delaySeconds)

    {

        Console.WriteLine(string.Format(" {0} 秒收启动火箭发射", delaySeconds));

        Thread.Sleep(1000 * delaySeconds);

        Console.WriteLine("恭喜, 你的火箭发射成功");

    }

}

是时候来创建我们第一个拦截器了.我们需要继承实现IInterceptor ,这个接口最终会被DynamicProxy使用.

正如你在下面看到的,我们在方法进入时进行日志记录,通过调用invocation.Proceed()来执行真正的业务行为,然后在方法执行成功后、发生异常和退出时分别进行了日志记录。我们不在需要在我们的业务模型中编写相关日志记录的代码。我们只需要将LoggingInterceptor附加到需要日志记录的组件上。

internal class LoggingInterceptor : IInterceptor

{

    public void Intercept(IInvocation invocation)

    {

        var methodName = invocation.Method.Name;

        try

        {

            Console.WriteLine(string.Format("执行方法:{0}, 参数: {1}", methodName, string.Join(",", invocation.Arguments)));

            invocation.Proceed();

            Console.WriteLine(string.Format("成功执行了方法:{0}", methodName));

        }

        catch (Exception e)

        {

            Console.WriteLine(string.Format("方法:{0}, 异常信息:{1}", methodName, e.Message));

            throw;

        }

        finally

        {

            Console.WriteLine(string.Format("退出方法:{0}", methodName));

        }

    }

}

DynamicProxy 代理提供的对象是非常有用的。它使你可以访问当前方法的方法信息、参数、返回代码值和许多其他细节,如你下面看到的。.

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 container (IWindsorContainer)创建静态实例, 使用组件注册信息对它进行初始化(ComponentRegistration)。

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>();

    }

}

在控制台应用中启动应用程序

private static void Main(string[] args)

{

 

    DependencyResolver.Initialize();

 

    //resolve the type:Rocket

    var rocket = DependencyResolver.For<IRocket>();

 

    //method call

    try

    {

        rocket.Launch(5);

    }

    catch (Exception ex)

    {

    }

    System.Console.ReadKey();

}

让我们看一下控制台的输出。 不出所料,我们的LoggingInterceptor拦截方法调用并自动记录方法进入和退出。由于动态代理!. Thanks to DynamicProxy !

知识点

这是一个介绍性的文章,使初学者和中级开发人员理解使用 Castle Windsor DynamicProxy来理解AOP的基本概念。在未来的几天,我将不断更新这篇文章,以演示如何在一个Web Api项目中使用Log4net和动态代理在实现此日志记录解决方案

在C#中使用CastleDynamicProxy 实现AOP的更多相关文章

  1. Castle框架中的IOC和AOP机制

    反转控制(IOC)和面向切面编程(AOP)技术作为当前比较流行的技术,其优势已受到广泛关注,但是这两项新技术在实际项目上的应用研究却很落后,而且在.NET平台下实现这两项技术没有形成可以广泛套用的框架 ...

  2. 理解Spring中的IOC和AOP

    我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过ses ...

  3. 详谈 Spring 中的 IOC 和 AOP

    这篇文章主要讲 Spring 中的几个点,Spring 中的 IOC,AOP,下一篇说说 Spring 中的事务操作,注解和 XML 配置. Spring 简介 Spring 是一个开源的轻量级的企业 ...

  4. Spring中基于xml的AOP

    1.Aop 全程是Aspect Oriented Programming 即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术.Aop是oop的延续,是软件开发中的 一个热点 ...

  5. .Net中的RealProxy实现AOP

    序言 这个AOP要从我们公司的一个事故说起,前段时间公司的系统突然在乌云中出现,数据被泄露的一览无余,乌云上显示是SQL注入攻击.呵,多么贴近生活的一个露洞,可谓是人尽皆知啊.然而却华丽丽的给拉我们一 ...

  6. Spring中的IOC\DI\AOP等概念的简单学习

    IoC(Inversion of Control,控制反转).这是spring的核心,贯穿始终, 所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.Spr ...

  7. Spring AOP报错处理 Can not set field to $Proxy 在spring中使用事物或AOP遇到的错误

    [转] 解决方法: http://forum.springsource.org/showthread.php?85016-IllegalArgumentException-with-Applicati ...

  8. SpringMVC中对Controller使用AOP

    转自http://usherlight.iteye.com/blog/1306111 正确配置spring aop,在controller中使用AOP 在controller中使用AOP的问题主要在于 ...

  9. spring中依赖注入与aop讲解

    一.依赖注入 这个属于IOC依赖注入,也叫控制反转,IOC是说类的实例由容器产生,而不是我们用new的方式创建实例,控制端发生了改变所以叫控制反转. 1 2 3 4 5 6 7 8 9 10 11 1 ...

随机推荐

  1. 使用安卓中的TextToSpeech控件实现朗读文字

    首先感谢原文的博主,本文中的代码均来自该博主:(原文地址)http://flycatdeng.iteye.com/blog/1827245 朗读文字不需要任何的权限,这个控件的好处是首先不要权限,其次 ...

  2. 没有暑假的Ada 要好好努力咯 C#继续

  3. OpenSSl编译

    1.下载openssl代码,下载地址:http://www.openssl.org/source/ ,如果使用winrar解压失败的话(提示不能创建符号链接),可以关闭UAC.2.下载安装Active ...

  4. (原)error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5577534.html 在debug下使用intel的mkl库时(release下无此问题),莫名的出现 ...

  5. 读取xml文件转成List<T>对象的两种方法(附源码)

    读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最近项目中用到的读取xml文件并且转成List<T>对象的方法, ...

  6. php 程序员的历程

    今天一朋友该找工作了. 问了我好多 我整理了下  希望有些帮助 以下内容纯属个人感觉如果有不恰当的地方请忽略.... 我做的是项目的包工 就是把销售拿下的项目整合后给我们实现功能. --------- ...

  7. Lost Cows(BIT poj2182)

    Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10609   Accepted: 6797 Descri ...

  8. CSS之Hack

    一.类内部Hack IE都能识别*;标准浏览器(如FF)不能识别*:IE6能识别*,但不能识别 !important, IE7能识别*,也能识别!important; FF不能识别*,但能识别!imp ...

  9. 关于Winsock编程中IO重叠的概念

    我在看<Windows网络与通信程序设计>(王艳平)这本书时,对重叠IO很不理解,突然就冒出这么一个概念,没一点头绪.就目前的理解做一个整理. 第一种理解:OVERLAPPED,顾名思义为 ...

  10. Amazon Redshift and Massively Parellel Processing

    Today, Yelp held a tech talk in Columbia University about the data warehouse adopted by Yelp. Yelp u ...