原文链接: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. MVC中的View2(转)

    MVC中View是专门用来向浏览器显示结果的,它只负责把传入到View的数据展现给用户: 一,自定义view引擎:实现IViewEngine接口 namespaceSystem.Web.Mvc { p ...

  2. SQL FOR XML PATH 用法

    FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作.那么以一个实例为主 ...

  3. js静态方法

    1.ajax() 方法是属于“函数”本身的,和返回的对象没有关系 2.bark药调用,必须药new Hashiqi()得到对象,且由返回对象才能调用 3.ajax()方法药调用,不需要new对象,直接 ...

  4. IOS UI篇—UILabel的文字顶部对齐

    UILabel的文字顶部对齐 NOV 20TH, 2011 默认UILabel是垂直居中对齐的,如果你的UILabel高度有多行,当内容少的时候,会自动垂直居中. 如下图所示(图片来自stackove ...

  5. select选项改变时获取选中的option的值

    本来天真的以为直接this.value()就能去到select的值,可事实并非那么回事. <script> document.getElementById('select').onchan ...

  6. EC读书笔记系列之1:条款1、条款2、条款3

    条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...

  7. vs2010中的外部依赖项的含义

    vs2010中的项目下拉列表下面有外部依赖项,里面显示的文件是你程序中显示包含的头文件所包含的的头文件.比如,你的main函数里面包含了windows.h头文件,而windows.h头文件又包含其他头 ...

  8. jQuery中的$.extend方法总结

    原文见:jQuery.extend()函数详解 Jquery的扩展方法extend是我们在写插件的过程中常用的方法,但是经常容易搞不清楚以下两个写法的关系: 1.$.extend(dest,src1, ...

  9. 如何系统地学习JavaScript

    在过去,JavaScript只是被用来做一些简单的网页效果,比如表单验证.浮动广告等,所以那时候JavaScript并没有受到重视.自从AJAX开始流行后,人们发现利用JavaScript可以给用户带 ...

  10. java直接打开pdf,doc,xls

    jsp页面: <a href=\'#\' onclick=onLine(\''+urls[i]+'\') >在线打开</a> html页面超链接单击打开online函数 var ...