Mono.Cecil 初探(一):实现AOP
序言
本篇文章介绍基于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的更多相关文章
- 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 ...
- 基于Mono.Cecil的静态注入
Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了 动态注入有几种方式: 利用Remoting的ContextBoundObject或MarshalByRefObject. 动态代理( ...
- 编译时MSIL注入--实践Mono Cecil(1)
原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一 ...
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- 使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入 用于写Log) [此文报考 xxx is declared in another module and needs to be imported的解决方法]-摘自网络
目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 7. 怎么调用别的程序集的方法示例 8. [is declared in another module ...
- 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
原文 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...
- 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)
原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.. ...
- 使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试
Unity3D 引擎在 UnityEngine 名字空间下,提供了 Profiler 类(Unity 5.6 开始似乎改变了这个名字空间),用于辅助对项目性能进行测试.以 Android 平台为例 ...
- 巧用Mono.Cecil反射加载类型和方法信息
最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...
随机推荐
- MBR结构和DBR结构
- 用jdbc访问大段文本数据
package it.cast.jdbc; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.F ...
- Asp.Net Core 发布和部署(Linux + Jexus )
前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在 asp.net core 中对我们的已经完成的程序进行发布和部署. 有关如何使用 Nginx 进行部署, ...
- 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)
1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...
- 【译】PHP的变量实现(给PHP开发者的PHP源码-第三部分)
文章来自:http://www.aintnot.com/2016/02/12/phps-source-code-for-php-developers-part3-variables-ch 原文:htt ...
- Lesson 10 Not for jazz
Text We have an old musical instrument. It is called a clavichord. It was made in Germany in 1681. O ...
- Module Zero之用户管理
返回<Module Zero学习目录> 用户实体 用户管理者 用户认证 用户实体 用户实体代表应用的一个用户,它派生自AbpUser类,如下所示: public class User : ...
- 浅析Yii2的view层设计
Yii2.0的view层提供了若干重要的功能:assets资源管理,widgets小组件,layouts布局... 下面将通过对Yii2.0代码直接进行分析,看一下上述功能都是如何实现的,当然细枝末节 ...
- SQL Server 更改跟踪(Chang Tracking)监控表数据
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...
- UITableView 一直显示滚动条(ScrollBar Indicators)、滚动条Width(宽度)、滚动条Color(颜色)
在 IOS 中,对 UIScrollView 的滚动条(ScrollBar Indicators)的自定义设置接口,一直都是很少的.除了能自定义简单的样式(UIScrollViewIndicatorS ...