使用PostSharp进行AOP框架设计:一个简单的原型
AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。
在Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。
前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;
早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhen的PostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:
和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。
- 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
- 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
- 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
- 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
- 还可以拦截 Field Access、Exception 等操作。
- 无需将对象创建代码改成 "new proxy()",更加透明。
- 可以使用通配符进行多重拦截匹配。
- 静态注入带来的问题更多的是注入代码的质量和调试复杂度。
另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。
我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;
按以前的写法我们可能很麻烦,我们要如此这般的写:
{
public bool Add(string id, string orderName)
{
try
{
if (User.AddEnable)
{
//TODO:新增订单的实现
Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
Console.ReadLine();
Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
return true;
}
else
{
//
}
}
catch (Exception)
{
//TODO:记录异常的实现
throw;
}
return true;
}
public bool Delete(string id)
{
try
{
if (User.DeleteEnable)
{
//TODO:删除订单的实现
Console.WriteLine("您删除订单成功:编号:{0}", id);
}
else
{
//
}
}
catch (Exception)
{
//TODO:记录异常的实现
throw;
}
return true;
}
这种写的弊端我就不多说了,有很多先驱都阐述过……
我要演示的是采用AOP技术的框架原型实现:
首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)
然后我们实现Orders对象
namespace PostSharp.Demo
{
public class Orders
{
[Permission]
[Exception]
public bool Add(string id, string orderName)
{
Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
Console.ReadLine();
Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
return true;
}
[Logger]
[Permission]
[Exception]
public bool Delete(string id)
{
Console.WriteLine("您删除订单成功:编号:{0}", id);
return true;
}
}
}
当然还要模拟一个用户资格认证
{
/// <summary>
/// 静态的用户对象,用于存放当前登录用户,成员资格
/// </summary>
public static class User
{
private static string _userId;
public static string UserId
{
get { return _userId; }
set { _userId = value; }
}
public static bool AddEnable
{
get
{
return (_userId.ToLower() == "admin");
}
}
public static bool DeleteEnable
{
get
{
return (_userId.ToLower() == "admin");
}
}
}
}
再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……
PermissionAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public class PermissionAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
if (!User.AddEnable)
{
Console.WriteLine("用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);
eventArgs.FlowBehavior = FlowBehavior.Return;
}
}
}
}
LoggerAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public sealed class LoggerAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
DateTime time = DateTime.Now;
string log = "时间:{0},操作人员:{1},操作:{2}!";
object[] arg = eventArgs.GetArguments();
log = String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!");
System.IO.File.WriteAllText("C:\\Log.Txt", log);
}
}
}
ExceptionAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public class ExceptionAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
Console.WriteLine("程序出现异常:{0}", eventArgs.Exception.Message);
eventArgs.FlowBehavior = FlowBehavior.Return;
}
}
}
然后再用控制台程序测试下能不能成功
Console.WriteLine("请输入用户名:");
User.UserId = Console.ReadLine();
Console.WriteLine("请输入密码:");
Console.ReadLine();
string id;
LRedo:
Console.WriteLine("请输入您要执行的操作:新增(A),删除(D),退出(X)");
string opt = Console.ReadLine();
if (opt.ToLower() == "a")
{
Console.WriteLine("请输入订单编号:");
id = Console.ReadLine();
Console.WriteLine("请输入订单名称:");
string name = Console.ReadLine();
order.Add(id, name);
}
else if (opt.ToLower() == "d")
{
Console.WriteLine("请输入订单编号:");
id = Console.ReadLine();
order.Delete(id);
}
else if (opt.ToLower() == "x")
{
}
else
{
Console.WriteLine("您的输入不正确,请重新输入!");
goto LRedo;
}
Console.WriteLine("按任意键退出……");
Console.ReadLine();
写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?
public class Orders
{
// Methods
static Orders()
{
if (!~PostSharp~Laos~Implementation.initialized)
{
LaosNotInitializedException.Throw();
}
~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);
~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);
~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);
~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);
~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);
~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);
~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);
~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);
~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);
}
private bool ~Delete(string id)
{
Console.WriteLine("您删除订单成功:编号:{0}", id);
return true;
}
public bool Add(string id, string orderName)
{
bool ~returnValue~1;
MethodExecutionEventArgs ~laosEventArgs~7;
try
{
object[] ~arguments~6 = new object[] { id, orderName };
~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~6);
~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);
if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)
{
return (bool) ~laosEventArgs~7.ReturnValue;
}
try
{
Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
Console.ReadLine();
Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
~returnValue~1 = true;
}
catch (Exception ~exception~2)
{
object[] ~arguments~3 = new object[] { id, orderName };
MethodExecutionEventArgs ~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~3);
~laosEventArgs~4.Exception = ~exception~2;
~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);
switch (~laosEventArgs~4.FlowBehavior)
{
case FlowBehavior.Continue:
goto Label_0145;
case FlowBehavior.Return:
~returnValue~1 = (bool) ~laosEventArgs~4.ReturnValue;
goto Label_0145;
}
throw;
}
Label_0145:
~laosEventArgs~7.ReturnValue = ~returnValue~1;
~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);
~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;
}
catch (Exception ~exception~5)
{
~laosEventArgs~7.Exception = ~exception~5;
~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);
switch (~laosEventArgs~7.FlowBehavior)
{
case FlowBehavior.Continue:
return ~returnValue~1;
case FlowBehavior.Return:
return (bool) ~laosEventArgs~7.ReturnValue;
}
throw;
}
finally
{
~laosEventArgs~7.ReturnValue = ~returnValue~1;
~PostSharp~Laos~Implementation.~aspect~1.OnExit(~laosEventArgs~7);
~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;
}
return ~returnValue~1;
}
[DebuggerNonUserCode]
public bool Delete(string id)
{
bool ~returnValue~2;
MethodExecutionEventArgs ~laosEventArgs~8;
try
{
object[] ~arguments~7 = new object[] { id };
~laosEventArgs~8 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~7);
~PostSharp~Laos~Implementation.~aspect~2.OnEntry(~laosEventArgs~8);
if (~laosEventArgs~8.FlowBehavior == FlowBehavior.Return)
{
return (bool) ~laosEventArgs~8.ReturnValue;
}
try
{
Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Delete);
object[] arguments = new object[] { id };
MethodInvocationEventArgs eventArgs = new MethodInvocationEventArgs(delegateInstance, arguments);
~PostSharp~Laos~Implementation.~aspect~5.OnInvocation(eventArgs);
~returnValue~2 = (bool) eventArgs.ReturnValue;
}
catch (Exception ~exception~3)
{
object[] ~arguments~4 = new object[] { id };
MethodExecutionEventArgs ~laosEventArgs~5 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~4);
~laosEventArgs~5.Exception = ~exception~3;
~PostSharp~Laos~Implementation.~aspect~4.OnException(~laosEventArgs~5);
switch (~laosEventArgs~5.FlowBehavior)
{
case FlowBehavior.Continue:
goto Label_0160;
case FlowBehavior.Return:
~returnValue~2 = (bool) ~laosEventArgs~5.ReturnValue;
goto Label_0160;
}
throw;
}
Label_0160:
~laosEventArgs~8.ReturnValue = ~returnValue~2;
~PostSharp~Laos~Implementation.~aspect~2.OnSuccess(~laosEventArgs~8);
~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;
}
catch (Exception ~exception~6)
{
~laosEventArgs~8.Exception = ~exception~6;
~PostSharp~Laos~Implementation.~aspect~2.OnException(~laosEventArgs~8);
switch (~laosEventArgs~8.FlowBehavior)
{
case FlowBehavior.Continue:
return ~returnValue~2;
case FlowBehavior.Return:
return (bool) ~laosEventArgs~8.ReturnValue;
}
throw;
}
finally
{
~laosEventArgs~8.ReturnValue = ~returnValue~2;
~PostSharp~Laos~Implementation.~aspect~2.OnExit(~laosEventArgs~8);
~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;
}
return ~returnValue~2;
}
}
代码很简单,我是采用控制台应用实现的,如果您有兴趣,请下载Demo源码玩玩。
转载于:https://www.cnblogs.com/Hedonister/archive/2007/09/13/892107.html
使用PostSharp进行AOP框架设计:一个简单的原型相关推荐
- 初学者-如何使用bootstrap框架设计一个简单的网页主界面HTML+CSS+Bootstrap
自己也刚刚开始接触框架,在学习了bootstrap框架过后,练习写了一个简单的主界面,主界面的图如下: 这个页面主要用的bootstrap的栅格系统进行整体布局,网页效果简约大方,最重要的是比较简单吧 ...
- aop框架的一个简单实现
2019独角兽企业重金招聘Python工程师标准>>> 一.概述 如果传入的是java.util.ArrayList,则返回java.util.ArrayList:如果是ProxyF ...
- 如何设计一个简单的KV数据库
下面的内容仅供设计一个简单的KV数据库.如果想要实现一个功能更强的KV数据库的话,还需要考虑:更加丰富的数据类型.数据压缩.过期机制.数据淘汰策略.集群化.高可用等功能,另外还可以增加统计模块.通知模 ...
- 如何利用laragon框架制作一个简单的应用?
如何利用laragon框架制作一个简单的应用? 一.搭建环境 1. 安装Laragon 1.1 打开安装包用的语言 选择自己习惯用的语言 1.2 选择安装地址 1.3 选择Next,开始install ...
- 如何用Java设计一个简单的窗口界面(学习中.1)
如何用Java设计一个简单的窗口界面 一.前言 二.简单了解 1.Swing简介 2.框架(frame) 3.层次 三.步骤 1.打开eclipse,依次创建项目,包,类. 2.代码 2.1最简单的可 ...
- JAVA同时输入用户名和密码_用java模拟设计一个简单的“用户注册”程序。当用户输入用户名和密码时,单击“注...
用java模拟设计一个简单的"用户注册"程序.当用户输入用户名和密码时,单击"注 2020 - 9 - 26 TAG : 所有功能均已实现,如有不满意的地方我再修改imp ...
- python界面设计-手把手教你用Python设计一个简单的命令行界面
原标题:手把手教你用Python设计一个简单的命令行界面 对 Python 程序来说,完备的命令行界面可以提升团队的工作效率,减少调用时可能碰到的困扰.今天,我们就来教大家如何设计功能完整的 Pyth ...
- 设计一个简单分页存储管理系统_【系统架构】如何设计一个简单灵活的收银系统?看这里!(1)...
在电商项目中,收银系统是一个不可或缺的功能,因为你不仅要通过它来进行收款.退款,而且也要通过它进行财务的对账.报税等.因此,如何设计一个简单灵活的收银系统,对于开发电商项目来说非常重要. 那如何设计一 ...
- java完成一个学生信息调查程序_利用Java设计一个简单的学生信息管理程序
利用Java设计一个简单的控制台学生信息管理程序 此程序可作为课设的参考,其中信息存储于文件中. 创建了学生类Student,用于存储学号等的信息.创建StudentFunction类,用于实现诸如学 ...
最新文章
- PHP基础知识(三)
- 在项目里交叉使用Swift和OC
- cakephp oracle,Cakephp的魔法函数解析,findBy…
- 2012.2.18-silverlight设计器崩溃
- 【2015年第4期】大数据时代的数据挖掘 —— 从应用的角度看大数据挖掘(下)...
- Linux内核原理与分析-第二周作业
- Firefox推荐安装插件
- spark 类别特征_spark 机器学习基础 数据类型
- 库克:苹果正在开发“会震爆你”的未来产品
- Java项目集成海康威视门禁,NVR
- 应用工具推荐phpStudy(小皮面板)
- 房地产类软件实战教程,如何写好房地产类软文
- 验证sqlserver 2000 sp4补丁是否安装成功(安装补丁后可以远程访问)
- mysql最大整数类型_MySQL教程19-整数类型
- 2021强网杯 Web赌徒 WP
- getchar()函数的作用
- 报警器语音ic单片机芯片如何选型
- 解析机智云MCU源码
- java 有五个学生_《Java程序设计》 创建5个学生对象,给一个学生数组赋值,每个学生属性有:学号,姓名,年龄。...
- 计算机在职博士要考吗,在职博士容易考吗?
热门文章
- 一般项目的并发量有多少_汽车保养一般包含哪些项目、保养周期是多少
- sumif三个条件怎么填_Excel根据条件进行求和的几个常用函数公式!
- 2019下半年系统集成项目管理工程师下午真题
- 第二章密码学基础与应用备考要点及真题分布
- Java中的方法(形参及实参)return返回类型
- Confluence 6 管理协同编辑 - 最大编辑者的限制
- arcgis10.1连接sqlserver数据库常见问题(转载)
- AFN的简单二次封装
- 一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(8)--提交表单操作...
- 【转载】利用压缩网页来提升网站浏览速度