转载https://www.cnblogs.com/niceWk/archive/2010/07/19/1780843.html

AOP魔法

今天你AOP了吗?谈到AOP,总有一种神秘的感觉,人类对于未知的东西一般都会有这种感觉,就像魔术,一旦揭开谜底,顿时豁然开朗。如果你愿意的话,那么就和我一起踏上AOP的揭秘之旅吧!

几年来一直为.NET框架不支持AOP特性耿耿于怀,尽管有许多第三方组件和工具在.NET平台下实现了AOP,而且其中不乏珍品,但或多或少存在着这样那样的限制。直到.NET4的发放,终于让我们有了机会来自己做一个AOP。

熬了几个夜,总算“有心不负功夫人”——DynamicAspect出世了!虽然还是在测试版阶段,但功能一点都不弱,如果你想体验一把的话,可以到这里去下一个玩玩。

不过在玩之前,你最好对AOP有那么一点点的概念,如果你全然不知AOP为何物的话,可以Google或者百度一番后,再回到这里听我摆龙套不迟。

怎么样?拿到DynamicAspect了吗?那么请随我继续前行吧。在下载的源代码包中含有一个Sample, 我们就从这个Sample开始!(强烈建议你打开VS2010,按部就班的输入下面的每一行代码。)

Sample程序实现一个极其简单的ATM功能,也就是模拟一次存款和取款的过程。

首先,在VS2010中创建一个控制台应用程序(Console Application)项目,忘记说了,是C#哦!VB的朋友别跑:),将其命名为BankSample

在项目中,添加一个新的Bank类,添加代码如下:(不想动手的话,就复制/粘贴吧 ^_^)

    class Bank
    {
        decimal _account;         public void Withdraw(decimal amount)
        {
            _account -= amount;
        }         public void Deposit(decimal amount)
        {
            _account += amount;
        }         public void ShowAccount()
        {
          Console.WriteLine("Your are account amount is {0: 0.00##}", _account);
        }         public decimal Account
        {
            get { return _account; }
        }
    }
 
代码相当的简单,Withdraw从银行取款,Deposit向银行存款,_account字段保存当前银行账户数额。ShowAccount方法显示当前账户信息,Account属性返回当前账户金额。
接下来,在ProgramMain方法中编写如下代码:
static void Main(string[] args)
{

    Bank bank = new Bank();


    Console.WriteLine("========Desposit money from bank account=============");
    Console.WriteLine("Please enter deposit amount : ");
    decimal amount = 0;
    while (true)
    {
        string s = Console.ReadLine();
        if (decimal.TryParse(s, out amount))
        {
            bank.Deposit(amount);
            bank.ShowAccount();
            break;
        }
        else
        {
            Console.WriteLine("The amount is incorrect, please input again: ");
        }
    }
    Console.WriteLine("========Withdraw money from bank account=============");
    Console.WriteLine("Please enter withdraw amount : ");
    while (true)
    {
        string s = Console.ReadLine();
        if (decimal.TryParse(s, out amount))
        {
            bank.Withdraw(amount);
            bank.ShowAccount();
            break;
        }
        else
        {
            Console.WriteLine("The amount is incorrect, please input again: ");
        }
    }
    Console.ReadKey();
}

代码主要分为两个部分,上半部分是存款操作,下半部分是取款操作。编译确保代码没有错误,然后运行。

让我们观察一下上面的过程,貌似少了点什么,对,需要做安全检测!也就是说至少在调用bank.Desposit()Bank.Withdraw()方法之前,我们要求用户输入用户名和密码。如果验证通过则继续,否则抛出安全异常。要实现这一步并不难,创建一个验证类来负责处理用户的安全验证。验证方法可以插入在Main方法的代码中,也可以插入在Bank类中需要验证的方法的代码中。考虑这样的一种情况,如果需要验证的不仅仅是Bank类的方法,在一个复杂的应用中可能有许多方法也需要做验证,那么你需要花费时间在这些代码中去插入调用验证方法的代码。更恐怖的是,如果验证的规则发生变化,比如说某些类可能需要不同的验证方式(通过调用不同的验证代码),那么你需要一一的找到这些地方,然后进行修改。故事终于出现冲突了,那就让我们来解决这个冲突吧。首先添加对DynamicAspect组件的引用,同时也添加对System.ComponentModel.Composition.dll的引用,然后像平常一样创建一个新的类:AuthenticationAspect,让这个类从AspectBase派生,在类中重载OnBeforeMethodCall方法,编写代码如下所示:

        public override void OnBeforeMethodCall(WeavingContext context)
        {
            if (context.InvokeMemberBinder.Name != "ShowAccount")
            {
                Console.WriteLine("Please enter user ID: ");
                var userid = Console.ReadLine();

                Console.WriteLine("Please enter password: ");
                var password = Console.ReadLine();

                if (CheckAccount(userid, password) == false)
                    throw new Exception("Invalid user account!");
            }
        }

上面代码是自解释的,所以就不再赘言了,至于WeavingContext的参数类型,只当做不存在吧(我们以后再来讨论它)。

下面是CheckAccount的方法和实现:

        private bool CheckAccount(string userid, string password)
        {
            return userid.ToLower() == "user" && password == "p@ssw0rd";
        }
出于演示的目的,我们使用硬编码,在实际的应用中可能需要连接到数据库或者从某个地方获取用户的安全信息。
为了让我们的故事能够流畅的进行,注意到在OnBeforeMethodCall方法的代码中当用户不能通过验证时,有一个异常被抛出,所以我们需要新的类来处理异常事件。在项目中新添一个类:ExceptionAspect同样让它从AspectBase派生,不过这次重载的是OnExceptionMethodCall方法,实现方法的代码如下:
 public override bool OnExceptionMethodCall(WeavingContext context, Exception ex)
{
     Console.WriteLine("{0}: {1}", ex.Message, ex.InnerException.Message);
     return true;
}
编译程序,确保代码没有错误,然后运行程序。什么?什么都没有发生!被忽悠了哈。且慢,引用刘谦的一句话,见证奇迹的时候到了。要做的就是对代码施加一种魔法,打开Program.cs文件,对Main方法中的的开始处作如下变化:
       static void Main(string[] args)
        {
           // Bank bank = new Bank();
            dynamic bank = new Bank().AsDynamic<Bank>();
 
如果出现波浪线,请添加相应的using语句。再次运行程序,相信我不说你都看到了。
 

没有悬念了,如果你还意犹未尽的话,我们在给这个故事一个比较完美的结局,想像一下这样的场合:如果用户输入的金额为负,会发生什么?另外如果取款的时候透支了(假如该银行不支持透支)又将如何?那就是我们需要对输入的金额(也就是方法的参数进行校验)。在项目中在添加一个新的类:ValidatorAspect, 一样从AspectBase派生。重载并实现OnBeforeMethodCall方法如下所示:

public override void OnBeforeMethodCall(WeavingContext context)
{     var methodName = context.InvokeMemberBinder.Name;
    if (methodName == "Withdraw" || methodName == "Deposit")
    {
        var amount = (decimal)context.ArgumentValues[0];
        if (amount <= 0)
            throw new Exception("Amount should be greater than 0");         if (methodName == "Withdraw" && context.Target is Bank)
        {
            var bank = (Bank)context.Target;
            if (amount > bank.Account)
                throw new Exception("Amount is greater than current account.");
        }
   }
}
 
由于我们已经对代码施加过魔法了,那就编译并运行来验证不同的参数的情况。
从下一篇开始,我们将详细讲述DynamicAspect的实现原理以及一些高级应用案例。
(未完待续)

使用dynamic 和MEF实现轻量级的 AOP 组件 (1)的更多相关文章

  1. 使用dynamic和MEF实现轻量级的AOP组件 ---- 系列文章

      .NET 4 实践 - 使用dynamic 和MEF实现轻量级的AOP组件(1)   .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (2) .NET 4 实践 - 使用 ...

  2. 使用dynamic和MEF实现轻量级的AOP组件 (2)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/21/1782092.html 偷梁换柱 上一篇我们初试了DynamicAspect这把小刀,如果你 ...

  3. 使用dynamic和MEF实现轻量级的AOP组件 (3)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...

  4. .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...

  5. C++11实现一个轻量级的AOP框架

    AOP介绍 AOP(Aspect-Oriented Programming,面向方面编程),可以解决面向对象编程中的一些问题,是OOP的一种有益补充.面向对象编程中的继承是一种从上而下的关系,不适合定 ...

  6. C#轻量级高性能日志组件EasyLogger

    一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第六部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...

  7. 基于DispatchProxy打造自定义AOP组件

    DispatchProxy是微软爸爸编写的一个代理类,基于这个,我扩展了一个AOP组件 暂时不支持依赖注入构造方法,感觉属性注入略显麻烦,暂时没打算支持 基于特性的注入流程 [AttributeUsa ...

  8. 使用MEF与Castle实现AOP

    MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了.现在我们扩展MEF,在其装配生成实例时,使用Castle Dy ...

  9. 基于微软企业库的AOP组件(含源码)

    软件开发,离不开对日志的操作.日志可以帮助我们查找和检测问题,比较传统的日志是在方法执行前或后,手动调用日志代码保存.但自从AOP出现后,我们就可以避免这种繁琐但又必须要实现的方式.本文是在微软企业库 ...

随机推荐

  1. Attention-based Extraction of Structured Information from Street View Imagery:基于注意力的街景图像提取结构化信息

    基于注意力的街景图像提取结构化信息 一种用于真实图像文本提取问题的TensorFlow模型. 该文件夹包含在FSNS数据集数据集上训练新的注意OCR模型所需的代码,以在法国转录街道名称. 您还可以使用 ...

  2. Crash

    一.Crash类型 crash 一般产生自 iOS 的微内核 Mach,然后在 BSD 层转换成 UNIX SIGABRT 信号,以标准 POSIX 信号的形式提供给用户.NSException 是使 ...

  3. 树莓派 Raspberry PI之GPIO

    树莓派 Raspberry PI之GPIO 树莓派各版本硬件原理图:https://www.raspberrypi.org/documentation/hardware/raspberrypi/REA ...

  4. Android 数据库框架 DBFlow 的使用

    原文首发于微信公众号:jzman-blog,欢迎关注交流! DBFlow 是一个基于注解处理器开发的使用方便的 ORM Android 数据库,该库简化了很多多余的代码,并且提供了好用的 API 来处 ...

  5. springboot项目启动-自动创建数据表

    很多时候,我们部署一个项目的时候,需要创建大量的数据表.例如mysql,一般的方法就是通过source命令完成数据表的移植,如:source /root/test.sql.如果我们需要一个项目启动后, ...

  6. 分派pie(二分法)

    2.问题描述 我的生日要到了!根据习俗,我需要将一些派分给大家.我有N个不同口味.不同大小的派.有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成:可以是一整个派 ...

  7. 3.26java作业

    1.编写程序, 输入变量x的值,如果是1,输出x=1,如果是5,输出x=5,如果是 10,输出 x=10,除了以上几个值,都输出x=none.(知识点:if条件语句) package fda; imp ...

  8. 程序开发中的术语,如IDE,OOP等等

    我们在开发程序过程中,会用到一些与编译有关的术语,比如:[编辑器.编译器.调试器.连接器,链接器.解释器,集成开发环境(Integrated Development Environment,IDE). ...

  9. Appium自动化(2) - appium环境安装常见问题的解决方案

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 问题1:adb检测不到设备 解决 ...

  10. Hadoop(九):Shuffle组件

    重温MR整体流程 工作流程 开始执行输入(InputFormat),先对文件进行分片,然后读取数据输入到Map中. Mapper读取输入内容,解析成键值对,1行内容解析成1个键值对,每个键值对调用一次 ...