使用MEF与Castle实现AOP
MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了。现在我们扩展MEF,在其装配生成实例时,使用Castle DynamicProxy对其生成透明代理。
我们先实现一个拦截器,并且继承Attribute基类,这个我们可以将这个拦截器作为类的特性来使用。
- using Castle.DynamicProxy;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace MefAopTest
- {
- public class LogInterceptor : Attribute,IInterceptor
- {
- public void Intercept(IInvocation invocation)
- {
- Console.WriteLine("begin");
- invocation.Proceed();
- Console.WriteLine("end");
- }
- }
- }
这个拦截器中,我们对拦截的方法执行前和执行后都增加了操作。
然后我们新增一个类,这个类使我们需要导出的类。
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.Composition;
- using System.Linq;
- using System.Text;
- namespace MefAopTest
- {
- [Export(typeof(ClassA))]
- [LogInterceptor]
- public class ClassA
- {
- public virtual void GetA()
- {
- Console.WriteLine("GetA");
- }
- }
- }
在这个类上,我们增加特性 [Export(typeof(ClassA))],这是MEF的基本用法。[LogInterceptor]是我们定义的拦截器,我们可以拦截GetA方法。需要拦截的方法必须是虚方法。
下面我们来扩展下MEF。
ExportProvider 类:检索与指定的 ImportDefinition 对象相匹配的导出。这个类的作用很明确,就是用来寻找与 ImportDefinition 对象匹配的ExportDefinition。
我们新增一个基础自ExportProvider 的类。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ComponentModel.Composition.Hosting;
- using System.ComponentModel.Composition.Primitives;
- using Castle.DynamicProxy;
- namespace MefAopTest
- {
- public class AOPExportProvider : ExportProvider, IDisposable
- {
- private CatalogExportProvider _exportProvider;
- public AOPExportProvider(Func<ComposablePartCatalog> catalogResolver)
- {
- _exportProvider = new CatalogExportProvider(catalogResolver());
- }
- public ExportProvider SourceProvider
- {
- get
- {
- return _exportProvider.SourceProvider;
- }
- set
- {
- _exportProvider.SourceProvider = value;
- }
- }
- protected override IEnumerable<Export> GetExportsCore(
- ImportDefinition definition, AtomicComposition atomicComposition)
- {
- IEnumerable<Export> exports = _exportProvider.GetExports(definition, atomicComposition);
- return exports.Select(export => new Export(export.Definition, () => GetValue(export)));
- }
- private object GetValue(Export innerExport)
- {
- object value = innerExport.Value;
- Type t = value.GetType();
- IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();
- ProxyGenerator generator = new ProxyGenerator();
- object proxy = generator.CreateClassProxy(value.GetType(), attribs);
- return proxy;
- }
- public void Dispose()
- {
- _exportProvider.Dispose();
- }
- }
- }
在装配时,会触发GetExportsCore方法,去寻找相对应的导出。我们在GetValue方法中,使用Castle生成动态代理。
- IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();
上面这行代码主要是从需要导出的类的自定义特性中,寻找拦截器。我们这里定义的是[LogInterceptor]。
然后我们再生成透明的动态代理
- ProxyGenerator generator = new ProxyGenerator();
- object proxy = generator.CreateClassProxy(value.GetType(), attribs);
下面我们新增一个窗体类,窗体上有一个按钮,点击按钮,触发ClassA实例的GetA方法。看是否可以进行拦截。
- namespace MefAopTest
- {
- public : Form
- {
- public Form1()
- {
- InitializeComponent();
- ComposeParts();
- }
- [Import(typeof(ClassA))]
- private ClassA c1;
- public void ComposeParts()
- {
- Func<ComposablePartCatalog> catalogResolver = () =>
- {
- var catalog = new AggregateCatalog();
- AssemblyCatalog assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
- catalog.Catalogs.Add(assemblyCatalog);
- return catalog;
- };
- AOPExportProvider provider = new AOPExportProvider(catalogResolver);
- CompositionContainer container = new CompositionContainer(provider);
- provider.SourceProvider = container;
- container.ComposeParts(this);
- }
- private void Test_Click(object sender, EventArgs e)
- {
- c1.GetA();
- }
- }
- }
在代理里,我们定义了一个字段,用来Import ClassA类。
- [Import(typeof(ClassA))]
- private ClassA c1;
在我们装配代码中,使用我们扩展的AopExportProvider

我们测试下,点击按钮,看看输出的情况。

好的,我们成功的拦截了ClassA的GetA方法,并在方法执行前和执行后都增加了操作。
这种AOP的实现,我们只需要在需要导出的类上增加一个特性就行了。如果有其他需求,我们可以再增加拦截器,并在相应的类上增加特性就行了,很方便。美中不足的是,需要按照MEF的方式去生成实例,不能像postsharp那样。
使用MEF与Castle实现AOP的更多相关文章
- 使用dynamic和MEF实现轻量级的AOP组件 ---- 系列文章
.NET 4 实践 - 使用dynamic 和MEF实现轻量级的AOP组件(1) .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (2) .NET 4 实践 - 使用 ...
- [AOP系列]Autofac+Castle实现AOP事务
一.前言 最近公司新项目,需要搭架构进行开发,其中需要保证事务的一致性,经过一番查找,发现很多博文都是通过Spring.Net.Unity.PostSharp.Castle Windsor这些方式实现 ...
- [AOP系列]Autofac+Castle实现AOP日志
一.前言 最近公司新项目,需要搭架构进行开发,其中需要对一些日志进行输出,经过一番查找,发现很多博文都是通过Spring.Net.Unity.PostSharp.Castle Windsor这些方式实 ...
- C#使用Castle实现AOP面向切面编程
Castle.Core 本质是创建继承原来类的代理类,重写虚方法实现AOP功能.个人觉得比Autofac用着爽 使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Castle.Core并安 ...
- 使用dynamic和MEF实现轻量级的AOP组件 (3)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...
- 使用dynamic和MEF实现轻量级的AOP组件 (2)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/21/1782092.html 偷梁换柱 上一篇我们初试了DynamicAspect这把小刀,如果你 ...
- 使用 Castle 实现 AOP,以及 Autofac 集成 Castle
Castle 是 2003 年诞生于 Apache Avalon 项目,目的是为了创建一个IOC 框架.发展到现在已经有四个组件: ORM组件:ActiveRecord IOC组件:Windsor 动 ...
- .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)
转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...
- 使用dynamic 和MEF实现轻量级的 AOP 组件 (1)
转载https://www.cnblogs.com/niceWk/archive/2010/07/19/1780843.html AOP魔法 今天你AOP了吗?谈到AOP,总有一种神秘的感觉,人类对于 ...
随机推荐
- discrete
discrete - 必应词典 美[dɪ'skrit]英[dɪ'skriːt] adj.离散的:分离的:各别的 网络不连续的:分立的:离散型
- Intersection(Check)
Intersection http://poj.org/problem?id=1410 Time Limit: 1000MS Memory Limit: 10000K Total Submissi ...
- SQL SERVER 和ACCESS、EXCEL的数据导入导出
SQL SERVER 与ACCESS.EXCEL之间的数据转换SQL SERVER 和ACCESS的数据导入导出[日期:2007-05-06] 来源:Linux公社 作者:Linux 熟 悉 ...
- php Pthread 多线程 (二) Worker和Threaded
<?php //Worker是具有持久化上下文(执行环境)的线程对象 //Worker对象start()后,会执行run()方法,run()方法执行完毕,线程也不会消亡 class MySqlW ...
- 如何区分USB 2.0 和USB 3.0插口
USB3.0的速度是USB2.0的十倍,并且比USB2.0更加节能,同时,还能向下兼容USB2.0.那么,我们怎么区分USB2.0 和 USB 3.0呢. 电脑(有USB2.0和USB3.0的插口) ...
- beego启动找不到conf的原因
beego配置文件路径如下: app.conf内容 httpaddr = "192.168.199.178" httpport = appname = SecProxy runmo ...
- Phalcon Framework的MVC结构及启动流程分析
目前的项目中选择了Phalcon Framework作为未来一段时间的核心框架.技术选型的原因会单开一篇Blog另说,本次优先对Phalcon的MVC架构与启动流程进行分析说明,如有遗漏还望指出. P ...
- cubieboard安装小记
1.1.使用ttl线 ttl线驱动程序:PL2303_Prolific_DriverInstaller_v1.7.0.exe(驱动精灵上下载) ttl终端:http://the.earth.li/~s ...
- devart 放大招了
前面我纪念BDE 的文章里面说过,devart 会在今后在数据库存取技术上会有更大的 进步,没想到很快devart 放大招了.在最新的unidac 和sdac 中,devart 支持在非Windows ...
- idea开发工具下报Set language level to 6-@Override in interfaces的解决方法
idea开发工具下报Set language level to 6-@Override in interfaces的解决方法 实现接口时报如下错误:Set language level to 6-@O ...