序言

本篇文章介绍基于Mono.Cecil实现静态AOP的两种方式:无交互AOP和交互式AOP。

概念介绍

Mono.Cecil:一个可加载并浏览现有程序集并进行动态修改并保存的.NET框架。

AOP:面向切面编程。可以简单理解为程序中的每个类的方法均是一块“积木”,采用AOP把新增的“积木随心所欲地嵌入”到各个“积木”上面(前面)或下面(后面)。如下图所示:

                                                      

动态AOP:在运行时进行AOP。.NET现有.Net Remoting,Unity,Spring.NET,PostSharp,Mr Advice等多种框架可供使用。

静态AOP:相对于动态AOP,静态AOP是指在编译时、运行前就已经进行了AOP。.NET中一般通过修改编译生成的中间语言IL实现,Mono.Cecil就是实现静态AOP一个很好的方式。根据与原有程序交互的情况,本文把静态AOP分为无交互AOP和交互式AOP两种方式。

无交互AOP

与原有程序无任何“交集”,纯粹式的AOP。下面通过两个例子进行说明如何通过Mono.Cecil进行无交互AOP。

同一个方法内AOP

原程序:控制台打印出“Hello World”。代码如下:

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}

  

AOP需求:需要在打印前和打印后输出当前时间。

-添加Mono.Cecil.dll引用并添加以下代码

using Mono.Cecil;
using Mono.Cecil.Cil;

  

-定位方法(建议用Linq)

        AssemblyDefinition assembiy = AssemblyDefinition.ReadAssembly(Path);//Path: dll or exe Path
var method = assembiy.MainModule
.Types.FirstOrDefault(t => t.Name == "Program")
.Methods.FirstOrDefault(m => m.Name == "Main");

  

-获取IL

var worker = method.Body.GetILProcessor();//Get IL

-AOP Front

                string FrontTime = DateTime.Now.ToString();
var ins = method.Body.Instructions[0];//Get First IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Ldstr, FrontTime));
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }))));

-AOP Back

                string BackTime = DateTime.Now.ToString();
ins = method.Body.Instructions[method.Body.Instructions.Count - 1]; //Get Lastest IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Ldstr, BackTime));
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }))));

  

-保存修改

assembiy.Write(Path);

-结果

采用Refactor进行对比得知AOP已成功!

         

“跨类”AOP

此种方式指的是在方法前后通过指定调用其他类的方法实现AOP,可用于扩展功能,如日志记录,数据库记录等。

相对于同一个方法内的AOP,因为通过方法调用指定类的方法,实现更加灵活,功能扩展更加全面且在开发阶段可进行调试或单元测试,所以此种方式应用层面更为广泛。

下面将从静态和非静态两种方式进行代码实现。

原程序:控制台打印出“Hello World”

 class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}

AOP需求:需要把打印前的时间和打印后的时间记录到数据库中。

跨静态类/静态方法AOP

为示例简便,LogDT方法表示记录时间到数据库中(为方便显示,采用控制台打印的方式)

public  class LogDateTime_Static
{
public static void LogDT()
{
Console.WriteLine(DateTime.Now.ToString());
}
}

-AOP Front

//AOP_Front
var ins = method.Body.Instructions[];//Get First IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(LogDateTime).GetMethod("LogDT"))));//Call static Method

-AOP Back

//AOP_Back
ins = method.Body.Instructions[method.Body.Instructions.Count - ]; //Get Lastest IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(LogDateTime).GetMethod("LogDT"))));//Call static Method

-结果

      

跨非静态类AOP

非静态类实例代码如下:

public  class LogDateTime_NonStatic
{
public void LogDT()
{
Console.WriteLine(DateTime.Now.ToString());
}
}

-实例化指定类

 var Constructor = assembiy.MainModule.Import(typeof(LogDateTime_NonStatic).GetConstructor(new Type[] { }));//Create Instance

-AOP Front

var ins = method.Body.Instructions[];//Get First IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Newobj, Constructor));
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(LogDateTime_NonStatic).GetMethod("LogDT"))));////Call Instance Method

-AOP Back

 ins = method.Body.Instructions[method.Body.Instructions.Count - ]; //Get Lastest IL Step
worker.InsertBefore(ins, worker.Create(OpCodes.Newobj, Constructor));
worker.InsertBefore(ins, worker.Create(OpCodes.Call,
assembiy.MainModule.Import(typeof(LogDateTime_NonStatic).GetMethod("LogDT"))));////Call Instance Method

-结果

                 

Mono.Cecil 初探(一):实现AOP的更多相关文章

  1. C# Asp.net中的AOP框架 Microsoft.CCI, Mono.Cecil, Typemock Open-AOP API, PostSharp -摘自网络 (可以利用反射 Attribute 进行面向切面编程 可以用在记录整个方法的Log方面)

    Both Microsoft.CCI and Mono.Cecil are low-level, and don't validate produced assemblies. It takes lo ...

  2. 基于Mono.Cecil的静态注入

    Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了 动态注入有几种方式: 利用Remoting的ContextBoundObject或MarshalByRefObject. 动态代理( ...

  3. 编译时MSIL注入--实践Mono Cecil(1)

    原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一 ...

  4. 运用Mono.Cecil 反射读取.NET程序集元数据

    CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...

  5. 使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入 用于写Log) [此文报考 xxx is declared in another module and needs to be imported的解决方法]-摘自网络

    目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 7.  怎么调用别的程序集的方法示例 8. [is declared in another module ...

  6. 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)

    原文 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...

  7. 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

    原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.. ...

  8. 使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试

    Unity3D 引擎在  UnityEngine 名字空间下,提供了  Profiler 类(Unity 5.6 开始似乎改变了这个名字空间),用于辅助对项目性能进行测试.以 Android 平台为例 ...

  9. 巧用Mono.Cecil反射加载类型和方法信息

    最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...

随机推荐

  1. canvas初探2

    2.2 canvas的绘图环境 canvas仅仅只是一个绘图的容器,其内存在一个绘图环境,该环境对象提供了全部的绘图功能. 目前canvas的绘图环境是2d,但canvas规范在着手准备支持其他类型的 ...

  2. node(async原理)

    node中的async是用来实现同步操作的,提供包括map.Series等方法,本文不做赘述. 由于项目需要在浏览器端用了async.js,因此仔细看了下它的代码.原来,一直以为node是在服务端调用 ...

  3. Lesson 2 Breakfast or lunch?

    Text It was Sunday. I never get up early on Sundays. I sometimes stay in bed until lunchtime. Last S ...

  4. 如何理解T-SQL中Merge语句(二)

    写在前面的话:上一篇写了如何理解T-SQL中Merge语句,基本把Merge语句要讲的给讲了,在文章的后面,抛出了几个结,当时没有想明白怎么去用文字表达,这一篇就来解答一下这几个结,又是一篇“天马行空 ...

  5. 几个毫无节操纯属恶搞的JavaScript插件

    fartscroll.js,为放屁而生 你知道么,有了这个js库,你的页面就可以——————————放屁勒! 打开下面的演示地址,然后滚动页面. 在线演示:http://theonion.github ...

  6. ASP.NET MVC 从零开始 - 请求处理

    这篇文章是从我的 github 博客 lxconan.github.io 导入的. 这是这个系列的第三篇了.前两篇文章请参见: ASP.NET MVC 从零开始 - Create and Run AS ...

  7. 浅谈HTML5单页面架构(一)——requirejs + angular + angular-route

    心血来潮,打算结合实际开发的经验,浅谈一下HTML5单页面App或网页的架构. 众所周知,现在移动Webapp越来越多,例如天猫.京东.国美这些都是很好的例子.而在Webapp中,又要数单页面架构体验 ...

  8. 在UWP中页面滑动导航栏置顶

    最近在研究掌上英雄联盟,主要是用来给自己看新闻,顺便copy个界面改一下段位装装逼,可是在我copy的时候发现这个东西 当你滑动到一定距离的时候导航栏会置顶不动,这个特性在微博和淘宝都有,我看了@ms ...

  9. Constraint5:unique 约束和null

    unique约束使用unique index来限制列值的唯一性: 创建unique约束之后,column中允许插入null值,unique 约束将两个null值看作是相同的(即null=null为tr ...

  10. FontAwesome 4.4.0 中完整的585个图标样式CSS参考

    做一记录,免得每次都去网上搜图标对应的class. 在线版本:http://dnt.dkill.net/dnt/font/