Autofac 管理扩展框架 (MEF)
Autofac 的 MEF 集成允许您使用 管理扩展框架 在应用程序中暴露扩展点。
要在 Autofac 应用程序中使用 MEF,您必须引用 .NET 框架的 System.ComponentModel.Composition.dll
组件,并从 NuGet 获取 Autofac.Mef 包。
注意:这是一个单向操作 MEF 集成允许 Autofac 解决在 MEF 中注册的项,但不允许 MEF 解决在 Autofac 中注册的项。
在 Autofac 中使用 MEF 扩展
Autofac/MEF 集成允许将 MEF 目录注册到 ContainerBuilder
,然后使用 RegisterComposablePartCatalog()
扩展方法。
var builder = new ContainerBuilder();
var catalog = new DirectoryCatalog(@"C:\MyExtensions");
builder.RegisterComposablePartCatalog(catalog);
支持所有 MEF 目录类型:
TypeCatalog
AssemblyCatalog
DirectoryCatalog
一旦注册了 MEF 目录,其中的导出项可以通过 Autofac 容器或注入到其他组件来解决。例如,假设您有一个使用 MEF 属性定义导出类型的类:
[Export(typeof(IService))]
public class Component : IService { }
使用 MEF 目录,您可以注册该类型。Autofac 将找到导出的接口并提供服务。
var catalog = new TypeCatalog(typeof(Component));
builder.RegisterComposablePartCatalog(catalog);
var container = builder.Build();
// 解决得到的 IService 实现将由类型 Component 提供。
var obj = container.Resolve<IService>();
将 Autofac 组件提供给 MEF 扩展
Autofac 组件不会自动提供给 MEF 扩展导入。也就是说,如果您使用 Autofac 解决一个使用 MEF 注册的组件,只允许使用 MEF 注册的其他服务来满足其依赖关系。
要将 Autofac 组件提供给 MEF,请使用 Exported()
扩展方法:
builder.RegisterType<Component>()
.Exported(x => x.As<IService>().WithMetadata("SomeData", 42));
再次强调,这是一次性操作。它允许 Autofac 为在 Autofac 中注册的 MEF 组件提供依赖项 - 它不会将 Autofac 注册项导出到 MEF 目录中以供解决。
使用元数据
Autofac MEF 集成为现有的 Lazy<T>
支持添加了 Lazy<T, TMetadata>
关系支持。
例如,假设您有一个定义元数据的接口:
public interface IAgeMetadata
{
int Age { get; }
}
您可以注册 Autofac 服务并使用 Lazy<T, TMetadata>
关系,方法是添加 MEF 元数据注册源:
var builder = new ContainerBuilder();
// 这会添加 MEF 关系注册源。
builder.RegisterMetadataRegistrationSources();
builder.RegisterType<Component>()
.WithMetadata<IAgeMetadata>(m => m.For(value => value.Age, 42));
var container = builder.Build();
然后,您可以从此处解决 Lazy<T, TMetadata>
:
using (var scope = container.BeginLifetimeScope())
{
var lazy = scope.Resolve<Lazy<Component, IAgeMetadata>>();
// lazy.Metadata.Age == 42
}
已知问题:如果您在 MEF 的 [Imports]
上有一个 Lazy<T, TMetadata>
值,此时对象 T
不会延迟实例化。在 Autofac.Mef 仓库中已为此问题提交了一个问题。 如果您想帮忙,我们很乐意接受一个 PR!
已知问题/陷阱
- Autofac 和 MEF 的集成是单向的。 它不允许 MEF 组合容器访问在 Autofac 中注册的东西。相反,它基本上采用 MEF 注册语义,并帮助填充一个 Autofac 容器。之后,您期望从 Autofac 解决东西,而不是从 MEF 容器。
- 懒加载元数据导入不工作。 如果您有一个 MEF 的
[Imports]
在一个Lazy<T, TMetadata>
值上,此时对象T
不会延迟实例化。在 Autofac.Mef 仓库中已为此问题提交了一个问题。 - 不支持开放泛型导出。 如果您在一个 MEF 组件上有一个像
[Export(typeof(A<>))]
这样的属性,Autofac 将无法正确处理这个导出,解决此类类型的对象将失败。在 Autofac.Mef 仓库中已为此问题提交了一个问题。