MEF


  Managed Extensibility Framework(MEF)是一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)等。

  Fireasy 提供了对 MEF 的封装,位于 Fireasy.Common.Composition 命名空间下。


1、使用 Imports 静态类

  使用 Imports 静态类的 GetService 方法可以像 IServiceProvider 一样获取相关的实例。它的映射依赖于 ExportAttribute 特性。如下所示:

public interface IService
{
}

[Export(typeof(IService))]
public class ServiceImpl : IService
{
}

[TestMethod]
public void TestGetService()
{
    var obj = Imports.GetService<IService>();
    Assert.IsNotNull(obj);
}

  如果定义了多个实现类的话,可以使用 GetServices 方法可以获得所有实例。如下所示:

[Export(typeof(IService))]
public class ServiceImpl1 : IService
{
}

[Export(typeof(IService))]
public class ServiceImpl2 : IService
{
}

[TestMethod]
public void TestGetServices()
{
    var count = Imports.GetServices<IService>().Count();
    Assert.AreEqual(2, count);
}

  ExportAttribute 特性可以指定一个契约名称,Imports 类也可以根据契约名称获取相应的实例。如下所示:

[Export("One", typeof(IService))]
public class ServiceImpl1 : IService
{
}

[Export("Tow", typeof(IService))]
public class ServiceImpl2 : IService
{
}

[TestMethod]
public void TestGetServices()
{
    var obj = Imports.GetService<IService>("Tow");
    Assert.IsTrue(obj is ServiceImpl2);
}

2、部件目录

  默认的部件目录使用的是 AssemblyDirectoryCatalog 类,即在当应用程序目录下遍列所有程序集(*.dll),你可以设置 Container 属性来改变部件目录。如下所示:

[Export(typeof(IService))]
public class ServiceImpl1 : IService
{
}

[Export(typeof(IService))]
public class ServiceImpl2 : IService
{
}

[TestMethod]
public void TestSingleService()
{
    //使用 SingleCompositionContainer 后,只会从多个部件中导出一个实例
    Imports.Container = new CompositionContainer(new SingleCompositionContainer());
    var count = Imports.GetServices<IService>().Count();
    Assert.AreEqual(1, count);
}

  使用 ConventionalCatalog 类像 Container 一样手动添加接口与实现的映射;使用 FilterCompositionContainer 类指定导出的过滤函数。


3、配置

  使用配置,可以缩放部件目录所遍列的文件数量,提高程序的效率。使用配置后,部件目录对应的是 ConfigurationCatalog 类,它是基于以下的配置文件:

  • .Net Framework 下的 app.config 或 web.config 文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="fireasy">
      <section name="imports" type="Fireasy.Common.Composition.Configuration.ImportConfigurationSectionHandler, Fireasy.Common"/>
    </sectionGroup>
  </configSections>
  <fireasy>
    <imports>
      <import name="demo" assembly="demo" />
      <import name="import" importType="demo.IService, demo" />
    </imports>
  </fireasy>
</configuration>
  • .Net Core 下的 appsettings.json 文件
{
  "fireasy": {
    "imports": {
      "settings": {
        "demo": {
          "assembly": "demo"
        },
        "import": {
          "importType": "demo.IService, demo"
        }
      }
    }
  }
}