使用dynamic 和MEF实现轻量级的 AOP 组件 (1)
转载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属性返回当前账户金额。
接下来,在Program的Main方法中编写如下代码:
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)的更多相关文章
- 使用dynamic和MEF实现轻量级的AOP组件 ---- 系列文章
.NET 4 实践 - 使用dynamic 和MEF实现轻量级的AOP组件(1) .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (2) .NET 4 实践 - 使用 ...
- 使用dynamic和MEF实现轻量级的AOP组件 (2)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/21/1782092.html 偷梁换柱 上一篇我们初试了DynamicAspect这把小刀,如果你 ...
- 使用dynamic和MEF实现轻量级的AOP组件 (3)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...
- .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...
- C++11实现一个轻量级的AOP框架
AOP介绍 AOP(Aspect-Oriented Programming,面向方面编程),可以解决面向对象编程中的一些问题,是OOP的一种有益补充.面向对象编程中的继承是一种从上而下的关系,不适合定 ...
- C#轻量级高性能日志组件EasyLogger
一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第六部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...
- 基于DispatchProxy打造自定义AOP组件
DispatchProxy是微软爸爸编写的一个代理类,基于这个,我扩展了一个AOP组件 暂时不支持依赖注入构造方法,感觉属性注入略显麻烦,暂时没打算支持 基于特性的注入流程 [AttributeUsa ...
- 使用MEF与Castle实现AOP
MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了.现在我们扩展MEF,在其装配生成实例时,使用Castle Dy ...
- 基于微软企业库的AOP组件(含源码)
软件开发,离不开对日志的操作.日志可以帮助我们查找和检测问题,比较传统的日志是在方法执行前或后,手动调用日志代码保存.但自从AOP出现后,我们就可以避免这种繁琐但又必须要实现的方式.本文是在微软企业库 ...
随机推荐
- 食物图片变菜谱:这篇CVPR论文让人人都可以学习新料理
根据 Facebook 的统计,Instgram 上的美食图片数量已经超过 3 亿张.然而,获取食物烹饪方法的途径依然有限,例如,通过烹饪网站或相关教程.怎样能够挖掘丰富食物图片背后的烹饪方法,让每个 ...
- C++ STL 常用容器之 stack
C++ STL Container--Stack 栈是一种先进后出(LIFO)的数据结构,限制只能在一端完成插入和删除操作,这一端叫做栈顶(top),另一端即为栈底(bottom).C++ STL(S ...
- CodeForces - 1244D 树(一条链)的染色
题意:给一个无向的无环的树,需要用三种颜色将他染色,相邻的三个点不能有重复的颜色.给出每个点染成每种颜色的花费,求最小的染色花费,如果给的图不能按要求染色,输出-1. 思路:只有三种颜色,相邻三个点还 ...
- TCP漫谈之keepalive和time_wait
TCP是一个有状态通讯协议,所谓的有状态是指通信过程中通信的双方各自维护连接的状态. 一.TCP keepalive 先简单回顾一下TCP连接建立和断开的整个过程.(这里主要考虑主流程,关于丢包.拥塞 ...
- C 部落划分
时间限制 : - MS 空间限制 : - KB SPJ 评测说明 : 1s,128m 问题描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人 ...
- lly的数列询问(最小生成树 + 思维)
lly的数列询问 Description 这个问题很简单,lly lly lly给你一些提示,让你试着确定长度为n n n的数列A [1] A [2] ... A [n]的值,但是他想尽一切办法为大家 ...
- 本地代码上传到git仓库(github)
准备:拥有自己的github账号:电脑上安装了git; 1.进入github,进入仓库点击NEW(新建仓库) 2.新建仓库 Repository name :仓库名称: Description (op ...
- 简单分析ucenter 会员同步登录通信原理
1.用户登录discuz,通过logging.php文件中的函数uc_user_login对post过来的数据进行验证,也就是对username和password进行验证. 2.如果验证成功,将调用位 ...
- 十年测试老鸟告诉你--自动化测试选JAVA还是选Python--写给还在迷茫中的朋友
一.前言 Python和Java哪个更适合做自动化测试?这是很多测试工程师从功能跨入自动化纠结的问题,今天测试老鸟来带大家详细分析一下!写给还在迷茫中的朋友! 首先可以确认的是提出这个问题的肯定是一个 ...
- Git应用详解第五讲:远程仓库Github与Git图形化界面
前言 前情提要:Git应用详解第四讲:版本回退的三种方式与stash 这一节将会介绍本地仓库与远程仓库的一些简单互动以及几款常用的Git图形化界面,让你更加方便地使用git. 一.Git裸库 简单来说 ...