使用CompositionScopeDefinition在MEF中定义范围

时间:2013-06-05 14:54:12

标签: c# .net prism mef .net-4.5

在我的应用程序的根目录中,我有一个AggregateCatalog和一个CompositionContainer,如下所示:

AggregateCatalog aggregateCatalog = new AggregateCatalog();
CompositionContainer compositionContainer = new CompositionContainer(aggregateCatalog);

我的应用程序加载包含多个导出的模块,如下图所示。我想使用CompositionScopeDefinition来确定图中圈出的导出范围。

Module Export Diagram

See here for the class definitions.

// Create CompositionScopeDefinition.
TypeCatalog globalParts = new TypeCatalog(typeof(RequestListener));
TypeCatalog scopedParts = new TypeCatalog(typeof(RequestHandler), typeof(DataAccessLayer), typeof(Logger), typeof(DatabaseConnection));
CompositionScopeDefinition compositionScopeDefinition = new CompositionScopeDefinition(
    globalParts,
    new[] { new CompositionScopeDefinition(scopedParts, null) });

// Register CompositionScopeDefinition.
aggregateCatalog.Catalogs.Add(compositionScopeDefinition);

// Create an instance of RequestListener.
RequestListener requestListener = compositionContainer.GetExportedValue<RequestListener>();

但是,这会导致以下异常:

  
    

System.ComponentModel.Composition.ImportCardinalityMismatchException发生消息=未找到与约束匹配的导出:       ContractName MyNamespace.RequestListener       RequiredTypeIdentity MyNamespace.RequestListener InnerException:

  

如何使用CompositionScopeDefinition将我的作用域导出添加到现有的AggregateCatalog并使用我现有的CompositionContainer初始化它们?

更新

似乎使用AggregateCatalog的问题。如果我将CompositionScopeDefinition直接添加到CompositionContainer,一切正常,但这阻止我将其他目录添加到CompositionContainer。

1 个答案:

答案 0 :(得分:2)

我和在CodePlex上使用MEF的人交谈过。这基本上是他们的答案:

// Handy extension methods for dealing with CompositionScopeDefinition (Not relevant to this answer but useful).
public static class ComposablePartCatalogExtensions
{
    public static CompositionScopeDefinition AsScope(this ComposablePartCatalog catalog, params CompositionScopeDefinition[] children)
    {
        return new CompositionScopeDefinition(catalog, children);
    }

    public static CompositionScopeDefinition AsScopeWithPublicSurface<T>(this ComposablePartCatalog catalog, params CompositionScopeDefinition[] children)
    {
        IEnumerable<ExportDefinition> definitions = catalog.Parts.SelectMany((p) => p.ExportDefinitions.Where((e) => e.ContractName == AttributedModelServices.GetContractName(typeof(T))));
        return new CompositionScopeDefinition(catalog, children, definitions);
    }
}

AggregateCatalog aggregateCatalog = new AggregateCatalog();
AggregateCatalog childAggregateCatalog = new AggregateCatalog();
CompositionScopeDefinition compositionScopeDefinition = aggregateCatalog.AsScope(childAggregateCatalog.AsScope());
CompositionContainer compositionContainer = new CompositionContainer(compositionScopeDefinition);

TypeCatalog globalParts = new TypeCatalog(typeof(RequestListener));
TypeCatalog scopedParts = new TypeCatalog(typeof(RequestHandler), typeof(DataAccessLayer), typeof(Logger), typeof(DatabaseConnection));

aggregateCatalog.Catalogs.Add(globalParts);
childAggregateCatalog.Catalogs.Add(scopedParts);

RequestListener requestListener = compositionContainer.GetExportedValue<RequestListener>();

基本上,您不能将CompositionScopeDefinition放在AggregateCatalog中。因此,您可以反转关系,并在根级别具有CompositionScopeDefinition,并为您尝试表示的每个范围级别提供多个AggregateCatalog。这似乎很有效。您还可以获得使用单个CompositionContainer的额外好处。