C# 使用CompositionScopeDefinition在MEF中定义范围

C# 使用CompositionScopeDefinition在MEF中定义范围,c#,.net,prism,mef,.net-4.5,C#,.net,Prism,Mef,.net 4.5,在应用程序的根目录下,我有一个AggregateCatalog和一个CompositionContainer,如下所示: AggregateCatalog aggregateCatalog = new AggregateCatalog(); CompositionContainer compositionContainer = new CompositionContainer(aggregateCatalog); 我的应用程序加载包含多个导出的模块,如下图所示。我想使用CompositionS

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

AggregateCatalog aggregateCatalog = new AggregateCatalog();
CompositionContainer compositionContainer = new CompositionContainer(aggregateCatalog);
我的应用程序加载包含多个导出的模块,如下图所示。我想使用CompositionScopeDefinition来确定图表中圈出的导出的范围

//创建CompositionScopeDefinition。
TypeCatalog globalParts=新的TypeCatalog(typeof(RequestListener));
TypeCatalog scopedParts=新的TypeCatalog(typeof(RequestHandler)、typeof(DataAccessLayer)、typeof(Logger)、typeof(DatabaseConnection));
CompositionScopeDefinition CompositionScopeDefinition=新的CompositionScopeDefinition(
环球艺术,
新[]{new CompositionScopeDefinition(scopedParts,null)};
//寄存器组合范围定义。
aggregateCatalog.Catalogs.Add(compositionScopeDefinition);
//创建RequestListener的实例。
RequestListener RequestListener=compositionContainer.GetExportedValue();
但是,这会导致以下异常:

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

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

更新


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

我与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的简便扩展方法(与此答案无关,但很有用)。
公共静态类ComposablePartCatalogExtensions
{
公共静态CompositionScopeDefinition AsScope(此CompositionScopeCatalog目录,参数CompositionScopeDefinition[]子目录)
{
返回新的CompositionScopeDefinition(目录,子目录);
}
public static CompositionScopeDefinition asscopewithpublicssurface(此ComposablePartCatalog目录,参数CompositionScopeDefinition[]子项)
{
IEnumerable definitions=catalog.Parts.SelectMany((p)=>p.ExportDefinitions.Where((e)=>e.ContractName==AttributedModelServices.GetContractName(typeof(T)));
返回新的CompositionScopeDefinition(目录、子项、定义);
}
}
AggregateCatalog AggregateCatalog=新的AggregateCatalog();
AggregateCatalog childAggregateCatalog=新建AggregateCatalog();
CompositionScopeDefinition CompositionScopeDefinition=aggregateCatalog.AsScope(childAggregateCatalog.AsScope());
CompositionContainer CompositionContainer=新的CompositionContainer(compositionScopeDefinition);
TypeCatalog globalParts=新的TypeCatalog(typeof(RequestListener));
TypeCatalog scopedParts=新的TypeCatalog(typeof(RequestHandler)、typeof(DataAccessLayer)、typeof(Logger)、typeof(DatabaseConnection));
aggregateCatalog.Catalogs.Add(globalParts);
childAggregateCatalog.Catalogs.Add(scopedParts);
RequestListener RequestListener=compositionContainer.GetExportedValue();

本质上,您不能将CompositionScopeDefinition放置在AggregateCatalog中。因此,您可以反转关系,在根级别创建CompositionScopeDefinition,并为您试图表示的每个作用域级别创建多个AggregateCatalog。这似乎很有效。您还可以通过使用单个CompositionContainer获得额外的好处。

如何使用Prism Bootstrapper实现这一点?
// 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>();