MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了。现在我们扩展MEF,在其装配生成实例时,使用Castle DynamicProxy对其生成透明代理。
我们先实现一个拦截器,并且继承Attribute基类,这个我们可以将这个拦截器作为类的特性来使用。

  1. using Castle.DynamicProxy;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. namespace MefAopTest
  7. {
  8. public class LogInterceptor : Attribute,IInterceptor
  9. {
  10. public void Intercept(IInvocation invocation)
  11. {
  12. Console.WriteLine("begin");
  13. invocation.Proceed();
  14. Console.WriteLine("end");
  15. }
  16. }
  17. }

这个拦截器中,我们对拦截的方法执行前和执行后都增加了操作。

然后我们新增一个类,这个类使我们需要导出的类。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.Composition;
  4. using System.Linq;
  5. using System.Text;
  6. namespace MefAopTest
  7. {
  8. [Export(typeof(ClassA))]
  9. [LogInterceptor]
  10. public class ClassA
  11. {
  12. public virtual void GetA()
  13. {
  14. Console.WriteLine("GetA");
  15. }
  16. }
  17. }

在这个类上,我们增加特性 [Export(typeof(ClassA))],这是MEF的基本用法。[LogInterceptor]是我们定义的拦截器,我们可以拦截GetA方法。需要拦截的方法必须是虚方法。

下面我们来扩展下MEF。
ExportProvider 类:检索与指定的 ImportDefinition 对象相匹配的导出。这个类的作用很明确,就是用来寻找与 ImportDefinition 对象匹配的ExportDefinition。
我们新增一个基础自ExportProvider 的类。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel.Composition.Hosting;
  6. using System.ComponentModel.Composition.Primitives;
  7. using Castle.DynamicProxy;
  8. namespace MefAopTest
  9. {
  10. public class AOPExportProvider : ExportProvider, IDisposable
  11. {
  12. private CatalogExportProvider _exportProvider;
  13.  
  14. public AOPExportProvider(Func<ComposablePartCatalog> catalogResolver)
  15. {
  16. _exportProvider = new CatalogExportProvider(catalogResolver());
  17. }
  18.  
  19. public ExportProvider SourceProvider
  20. {
  21. get
  22. {
  23. return _exportProvider.SourceProvider;
  24. }
  25. set
  26. {
  27. _exportProvider.SourceProvider = value;
  28. }
  29. }
  30.  
  31. protected override IEnumerable<Export> GetExportsCore(
  32. ImportDefinition definition, AtomicComposition atomicComposition)
  33. {
  34. IEnumerable<Export> exports = _exportProvider.GetExports(definition, atomicComposition);
  35. return exports.Select(export => new Export(export.Definition, () => GetValue(export)));
  36. }
  37.  
  38. private object GetValue(Export innerExport)
  39. {
  40. object value = innerExport.Value;
  41.  
  42. Type t = value.GetType();
  43. IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();
  44.  
  45. ProxyGenerator generator = new ProxyGenerator();
  46. object proxy = generator.CreateClassProxy(value.GetType(), attribs);
  47. return proxy;
  48. }
  49.  
  50. public void Dispose()
  51. {
  52. _exportProvider.Dispose();
  53. }
  54. }
  55. }

在装配时,会触发GetExportsCore方法,去寻找相对应的导出。我们在GetValue方法中,使用Castle生成动态代理。

  1. IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();

上面这行代码主要是从需要导出的类的自定义特性中,寻找拦截器。我们这里定义的是[LogInterceptor]。
然后我们再生成透明的动态代理

  1. ProxyGenerator generator = new ProxyGenerator();
  2. object proxy = generator.CreateClassProxy(value.GetType(), attribs);

下面我们新增一个窗体类,窗体上有一个按钮,点击按钮,触发ClassA实例的GetA方法。看是否可以进行拦截。

  1. namespace MefAopTest
  2. {
  3. public : Form
  4. {
  5. public Form1()
  6. {
  7. InitializeComponent();
  8. ComposeParts();
  9. }
  10. [Import(typeof(ClassA))]
  11. private ClassA c1;
  12.  
  13. public void ComposeParts()
  14. {
  15. Func<ComposablePartCatalog> catalogResolver = () =>
  16. {
  17.  
  18. var catalog = new AggregateCatalog();
  19. AssemblyCatalog assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  20.  
  21. catalog.Catalogs.Add(assemblyCatalog);
  22. return catalog;
  23. };
  24.  
  25. AOPExportProvider provider = new AOPExportProvider(catalogResolver);
  26. CompositionContainer container = new CompositionContainer(provider);
  27. provider.SourceProvider = container;
  28. container.ComposeParts(this);
  29. }
  30.  
  31. private void Test_Click(object sender, EventArgs e)
  32. {
  33. c1.GetA();
  34. }
  35. }
  36. }

在代理里,我们定义了一个字段,用来Import ClassA类。

  1. [Import(typeof(ClassA))]
  2. private ClassA c1;

在我们装配代码中,使用我们扩展的AopExportProvider

 
image.png

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

 
image.png

好的,我们成功的拦截了ClassA的GetA方法,并在方法执行前和执行后都增加了操作。
这种AOP的实现,我们只需要在需要导出的类上增加一个特性就行了。如果有其他需求,我们可以再增加拦截器,并在相应的类上增加特性就行了,很方便。美中不足的是,需要按照MEF的方式去生成实例,不能像postsharp那样。

使用MEF与Castle实现AOP的更多相关文章

  1. 使用dynamic和MEF实现轻量级的AOP组件 ---- 系列文章

      .NET 4 实践 - 使用dynamic 和MEF实现轻量级的AOP组件(1)   .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (2) .NET 4 实践 - 使用 ...

  2. [AOP系列]Autofac+Castle实现AOP事务

    一.前言 最近公司新项目,需要搭架构进行开发,其中需要保证事务的一致性,经过一番查找,发现很多博文都是通过Spring.Net.Unity.PostSharp.Castle Windsor这些方式实现 ...

  3. [AOP系列]Autofac+Castle实现AOP日志

    一.前言 最近公司新项目,需要搭架构进行开发,其中需要对一些日志进行输出,经过一番查找,发现很多博文都是通过Spring.Net.Unity.PostSharp.Castle Windsor这些方式实 ...

  4. C#使用Castle实现AOP面向切面编程

    Castle.Core 本质是创建继承原来类的代理类,重写虚方法实现AOP功能.个人觉得比Autofac用着爽 使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Castle.Core并安 ...

  5. 使用dynamic和MEF实现轻量级的AOP组件 (3)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...

  6. 使用dynamic和MEF实现轻量级的AOP组件 (2)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/21/1782092.html 偷梁换柱 上一篇我们初试了DynamicAspect这把小刀,如果你 ...

  7. 使用 Castle 实现 AOP,以及 Autofac 集成 Castle

    Castle 是 2003 年诞生于 Apache Avalon 项目,目的是为了创建一个IOC 框架.发展到现在已经有四个组件: ORM组件:ActiveRecord IOC组件:Windsor 动 ...

  8. .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...

  9. 使用dynamic 和MEF实现轻量级的 AOP 组件 (1)

    转载https://www.cnblogs.com/niceWk/archive/2010/07/19/1780843.html AOP魔法 今天你AOP了吗?谈到AOP,总有一种神秘的感觉,人类对于 ...

随机推荐

  1. 转)ubuntu安装clang

    主要参考:http://blog.csdn.net/firebird321/article/details/48528569 1.下载源码 去http://llvm.org/releases/down ...

  2. 4-计算九位数以内各个位数字和为s的种类

    /*假设我们当前要求的是100以内各位数之和和等于s的数有多少个,可以想到就是10以内各位数之和等于s的数的个数再加上10到100内的各位数之和等于s的个数.令dp[i][j]就代表10的j次方内各位 ...

  3. URL统一资源定位符的组成

    URL:Uniform Resource Locator统一资源定位符 用于定位网络上我们需要访问的资源 组成:协议名称+域名+路径+资源的名称.如:https://img13.360img.com/ ...

  4. final修饰符:

    知识点: 1.final关键字用于修饰类.变量和方法 2.有点类似C#里的 sealed 关键字,用于表示它修饰的方法.变量和类不可以再被改变 3.final修饰变量时,表示该变量一旦获取了初始值,就 ...

  5. Legendre多项式

    Legendre多项式 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Legendre多项式的递归公式

  6. HTML5 history详解

    最近研究vue-router单页转跳而不向服务器请求的原理, 主要是HTML5 history以及hash的应用,支持history时使用history模式 下面详细学习了一下常用的history相关 ...

  7. Nginx的使用(反向代理,负载均衡)

    在我目前的工作内容中,接触到Nginx的用处无外乎两点: 1. 反向代理,解决前端跨域的问题 工作内容有门户的概念,就是将各个子系统集成到门户里,在门户里面访问,这样就很容易造成跨域的问题 那么解决的 ...

  8. Part 5 - Django ORM(17-20)

    https://github.com/sibtc/django-beginners-guide/tree/v0.5-lw from django.conf.urls import url from d ...

  9. 链家笔试链家——找寻最小消费获取最大平均分java

    链家找寻最小消费获取最大平均分 输入: 5 5 4#表示科目数n,每科最大分值r,平均分avg 5 2#每科的实际得分,分数加1分的消耗的能量 4 7 3 1 3 2 2 5 输出: 4 #到达n*a ...

  10. [转]谈谈 Mifare Classic 破解

    Mifare Classic 提供 1 Kb - 4Kb 的容量,现在国内采用的多数是 Mifare Classic 1k(S50)[后面简称 M1 卡] M1 卡有从 0 到 15 共 16 个扇区 ...