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的实现原理以及一些高级应用案例。
(未完待续)

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

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

  1. react如何控制全局loading_ReactJS实践(一)—— FrozenUI React化之Loading组件

    在前面我们通过四篇文章入门了React的大部分主要API,现在则开始进入实践环节. 实践系列的开篇打算拿我司的FrozenUI来试验,将其部分UI组件进行React化,作为第一篇实践文章,将以较简单的 ...

  2. jsx怎么往js里传参数_实践Vue 3.0做JSX(TSX)风格的组件开发

    作者:莫夭 转发链接:https://zhuanlan.zhihu.com/p/102668383 前言 我日常工作都是使用React来做开发,但是我对React一直不是很满意,特别是在推出React ...

  3. 组件化实践详解(二)

    在上一篇文章<组件化实践详解(一)>中我们介绍了组件化实践的目标和实践步骤,本文继续说说关于组件化实践遇到的问题及思考. 1.组件内的架构设计 这条本来我是不想写的,但是很多组件化的文章里 ...

  4. Vue项目如何提高效率?大厂2大实践总结告诉你

    对于从事前端工作的小伙伴,掌握Vue,React这样的框架可以说是前端基本功了.人人都会用,那我们怎样才能写得比别人优雅?比别人漂亮? 鉴于一线互联网大厂在前沿技术领域的持续研究和大规模投入,直接向他 ...

  5. Apache Ranger、业务背景、现状与需求、大数据安全组件介绍与对别、系统架构及实践、ranger admin、UserSync、plugin、权限模型、权限实现等

    26.2.1业务背景 26.2.1.1现状&&需求 26.2.2大数据安全组件介绍与对比 26.2.2.2 Apache Sentry 26.2.2.3 Apache Ranger 2 ...

  6. Service Mesh 高可用在企业级生产中的实践

    Service Mesh Virtual Meetup 是 ServiceMesher 社区和 CNCF 联合主办的线上系列直播.本期为 Service Mesh Virtual Meetup#1 , ...

  7. 如何动态的生成某种类型的集合呢_知乎画报」的移动端动态化工程实践

    本文基于移动端动态化方案在知乎原生推广落地页「知乎画报」上的实践经验,对该方案技术升级过程中的思考以及技术关键细节做了详尽的解读. 商业化是互联网公司发展的重要阶段,App 端的商业广告业务对移动端动 ...

  8. Vue中CSS模块化最佳实践

    Vue风格指南中介绍了单文件组件中的Style是必须要有作用域的,否则组件之间可能相互影响,造成难以调试. 在Vue Loader Scope CSS和Vue Loader CSS Modules两节 ...

  9. .net vue漂亮登录界面_基于 electron-vue 开发的音乐播放器「实践」

    作者:XiaoTuGou 转发链接:https://github.com/SmallRuralDog 前言 基于 electron-vue 开发的音乐播放器,界面模仿QQ音乐. 技术栈electron ...

  10. 云原生时代,OAM模型加持下的应用交付与管理实践

    近日,[CNBPA实践沙龙]第二期在线上顺利举行,灵雀云资深产品经理进行了 "云原生应用交付与管理--OAM模型实践"的主题分享,和来自金融.工业.能源等不同行业的近百位IT从业者 ...

最新文章

  1. javascript json和json字符串互转
  2. DiscuzX3.2,3.3升级DiscuzX3.4的详细教程!
  3. 2.Java异常学习
  4. python里的坑。http://www.pythoner.com/356.html
  5. 抖音数据统计_26万条抖音数据背后的推荐逻辑以及严重失调的男女比例
  6. 年薪35万的深度学习工程师,正面临数百万的人才缺口
  7. 麻省理工MIT发布首个贝叶斯「数据清洗」机器人!
  8. Python入门--try-except-else
  9. python中pass语句学习
  10. HLW8032在stm32f413zh上的移植(基于HAL库)
  11. iOS常见的加密方法有哪些
  12. R2统计学正确计算方法
  13. 使用python批量压缩图片分辨率到指定大小,替换之前的压缩Image.ANTIALIAS
  14. html5人脸拼图,面向眼机交互的界面控件设计方法研究.pdf
  15. 问卷调查的数据如何分析?
  16. [java 新手练习1]5x5横排竖排方阵代码(java)
  17. 【python数据分析(24)】Matplotlib库基本图形绘制(1)(线形图、柱状图、堆叠图、面积图、填图、饼图)
  18. 【笔记】H.265/HEVC 视频编码(四)——预测编码
  19. Charles介绍与使用
  20. 数值积分之龙贝格积分

热门文章

  1. 《算法图解》第五章 散列表 课后作业
  2. 【算法随记四】自动色阶、对比度、直方图均衡等算法的一些小改进。
  3. [tldk][dpdk][dev] TLDK--基于dpdk的用户态协议栈传输层组件简单调研
  4. sprint3个人总结
  5. iOS端im实时音视频功能快速开发实操指导!
  6. CodeForces 682E Alyona and Triangles (计算几何)
  7. 定制Ubuntu桌面
  8. 关于Merge的整理--AndroidScreenSlidePager开源库中用到的
  9. (笔试题)被3和5整除的数的和
  10. Delphi 之 定时器 (TTimer组件)