根据文档使用时无法从 Mef CompositionContainer 解析 Autofac 依赖项

Unable to resolve Autofac dependencies from a Mef CompositionContainer when used according to documentation

根据 http://docs.autofac.org/en/latest/integration/mef.html.

上的文档使用时,Mef CompositionContainer 无法解析 Autofac 依赖项

我有一个大型代码库,它广泛使用了 ServiceLocator 和单例...服务定位器通过使用缓存 System.ComponentModel.Composition.Hosting.CompositionContainer 来完成所有对象创建、组合等。 (另请注意,我们目前 use/need 元数据支持)我正在尝试从这个切换到更现代的架构。为此,现有的基于 Mef(基于“CompositionContainer”)的服务定位器必须与 Autofac IoC 容器合作。

下面的函数

  1. 创建一个 Mef CompositionContainer
  2. 证明 MEF 能够解决简单的导出问题
  3. 配置 Autofac 以使用 .Exported 扩展方法向 MEF 注册并导出 AutofacExport 到 MEF。
  4. 证明 Autofac 可以解析具有 Autofac 中定义的依赖项的 mef 组件
  5. 说明 Mef 无法解析具有 Autofac 依赖项的导出组件组件。

抛出的异常为:ImportCardinalityMismatchException("No exports were found that match the constraint: ContractName MefExportWithDependency RequiredTypeIdentity MefExportWithDependency"抛出。

public void MefResolve_ObjectWithDependency_CanResolveWhenAutofacRegistersDependeyncy2()
{
    //1. Initialize Mef
    var composablePartCatalogs = new List<ComposablePartCatalog>
    {
        new AssemblyCatalog(Assembly.GetExecutingAssembly())
        //A lot more here..
    };

    var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
    var container = new CompositionContainer(aggregateCatalog, true);
    //2. As expected this is resolved
    container.GetExport<MefExport>().Should().NotBeNull();

    //3. Initialize Autofac
    var builder = new ContainerBuilder();
    builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
    builder.RegisterComposablePartCatalog(aggregateCatalog);

    var ioc = builder.Build();

    //4. Here Autofac is correctly providing the dependency to the mef ImportingConstructor
    ioc.Resolve<MefExportWithDependency>().AutofacExport.Should().NotBeNull();

    //5. The next line will throw ImportCardinalityMismatchException
    container.GetExport<MefExportWithDependency>();
}

上面的代码需要定义以下 类:

public class AutofacExport { }

[Export]
public class MefExport { }

[Export]
public class MefExportWithDependency
{
    public AutofacExport AutofacExport { get; set; }

    [ImportingConstructor]
    public MefExportWithDependency(AutofacExport autofacExport)
    {
        AutofacExport = autofacExport;
    }
}

注意: 我也看过 https://www.nuget.org/packages/MefContrib.Integration.Autofac/ - 它承诺将 Mef 与 Autofac 集成。但是,我没能找到有关如何配置的相关文档,而且该软件包的用途也不多。

我认为您可能误解了 Autofac.Mef 包的工作方式。虽然它将 MEF 项目引入 Autofac,让 Autofac 了解 export/import 属性和在 MEF 目录中注册的项目,这是一种单向操作 - 它不会将 Autofac 注册推入 MEF 或允许MEF CompositionContainer 使用 Autofac.

我相信您想要的是您提到的 MefContrib.Integration.Autofac 程序包,它似乎允许事情从另一个方向流动 - 从 Autofac 到 MEF。

查看其工作原理的好地方是他们的存储库,他们在其中 some unit tests 显示了 MEF 正在解析 Autofac 项目的集成。这是一个这样的测试:

[Test]
public void ExportProviderResolvesServiceRegisteredByTypeTest()
{
    // Setup
    var builder = new ContainerBuilder();
    builder.RegisterType<AutofacOnlyComponent1>().As<IAutofacOnlyComponent>();
    var autofacContainer = builder.Build();
    var adapter = new AutofacContainerAdapter(autofacContainer);
    var provider = new ContainerExportProvider(adapter);

    var component = provider.GetExportedValue<IAutofacOnlyComponent>();
    Assert.That(component, Is.Not.Null);
    Assert.That(component.GetType(), Is.EqualTo(typeof(AutofacOnlyComponent1)));
}

如您所见,他们有一个适用于 Autofac 容器的适配器,可以将它们 "converts" 转换为 MEF 可以理解的内容。他们还有 some unit tests showing bi-directional integration - MEF 从 Autofac 解析,Autofac 从 MEF 解析。

我个人从未使用过该软件包,但我认为,如果您查看测试以及他们如何设置这些测试,它应该会让您上路。