【问题标题】:MEF Child Container Module Not InitializingMEF 子容器模块未初始化
【发布时间】:2011-09-29 05:43:59
【问题描述】:

我有一个简单的容器层次结构,其中一个父容器使用目录目录在 Shell MEFBootstrapper 中定义,子容器使用不同的目录从父容器中创建。

我的子容器也使用 DirectoryCatalog(与父容器不同的路径),我可以看到容器在运行时具有装配和零件信息。

但是,位于子容器中的模块的 Initialize() 方法永远不会被调用。

我的目标是将子容器用作会话构造,允许用户创建新会话并在它们之间切换。但是,如果我无法初始化组成模块(并将它们的视图放入区域中),我就会陷入困境。

我曾想过使用事件聚合器从我的会话管理器中引发一个事件,以允许模块侦听该事件并自行初始化,但这似乎也不起作用。

我。为什么在加载到子容器中的模块上不调用 Initialize ii.如何从容器实例“触发”初始化(在模块上下文之外?)您可以遍历容器中的程序集并以这种方式触发初始化吗???

[来自 shell 项目中的 MefBootstrapper]

    protected override DependencyObject CreateShell()
    {
        ExportProvider ep = this.Container as ExportProvider;
        this.Container.ComposeExportedValue(ep);

[来自管理我的会话(容器)的服务]

    [ImportingConstructor]
    public SessionService(ExportProvider provider)
    {

[新会话(容器)的构造函数]

    private void Init(ComposablePartCatalog catalog, ExportProvider provider, string name, int callId, bool useContextProxy)
    {
        this._Name = name;
        this._CallID = callId;
        this.startTime = DateTime.Now;
        this.appHost = new CompositionContainer(catalog, new ExportProvider[] { provider });
    }

=====

被要求包含未调用初始化方法的模块代码(尽管被加载到有问题的容器中......我什至可以懒惰地实例化模块,但直接调用 Initialize() 会导致注入操作在方法正确。

namespace Module1
{
//, InitializationMode = InitializationMode.OnDemand
[ModuleExport("Module1.ModuleInit", typeof(Module1.ModuleInit))]
public class ModuleInit : IModule
{
    private readonly IRegionManager _regionManager;
    public IServiceLocator _serviceLocator;

    [ImportingConstructor]
    public ModuleInit(IRegionManager regionManager, IServiceLocator serviceLocator)
    {
        _regionManager = regionManager;
        _serviceLocator = serviceLocator;
    }

    #region IModule Members


    public void Initialize()
    {
        // Use View Discovery to automatically display the MasterView when the TopLeft region is displayed.
        _regionManager.RegisterViewWithRegion(RegionNames.TopLeftRegion, () => _serviceLocator.GetInstance<MasterView>());
    }

    #endregion
}

}

【问题讨论】:

  • 你能展示一个带有Initialize方法的示例模块吗?
  • 当然,非常简单,直接来自 VS2010 中的 PRISM 模板项目:(见编辑)

标签: module prism mef containers hierarchy


【解决方案1】:

我下载了您的代码并查看了它。我马上就发现了问题。由于这样的 DirectoryCatalog,引导程序实际上正在获取导出:

DirectoryCatalog catalog = new DirectoryCatalog(".");
this.AggregateCatalog.Catalogs.Add(catalog);

这意味着您将从该目录中的程序集获取导出。所以你只需要将所有导出类型的程序集复制到“.”目录下,也就是执行目录(Debug/bin)。

只需将模块 1 和模块 2 复制到 bin 目录中,一切都会优雅地组合起来 :)

实际上,我发现应该复制 bin 目录中的模块的构建后事件不起作用。也许是因为你重命名了一些东西。因此,如果您希望它在构建后自动复制程序集,只需用这个替换实际的构建后事件:

copy "$(TargetDir)\$(TargetFileName)" "$(TargetDir)\..\..\..\Shell\bin\$(ConfigurationName)\"

【讨论】:

  • 再次感谢您抽出宝贵时间查看此内容。但是,如果我将 Module1 和 Module2 放在根目录中,它们将被加载到初始目录中,然后又可以从根 CompositionContainer 中使用。我的目标(也许是不明智的)是将 Module1 和 Module2 隔离到子 CompositionContainer only 中,以便根 CompositionContainer 满足这些模块的导入请求。 .只有子容器可以。但我开始认为这只是一个坏主意,我应该简单地将所有模块加载到一个目录/容器中。
  • 是的,它最有可能将您输入的所有内容导出到一个地方。如果您需要在需要时初始化模块,您可以通过将模块配置为 OnDemand 来延迟加载。
【解决方案2】:

这个问题我已经遇到过很多次了,解决起来真的很简单。

从你的模块中移除构造函数。 Prism 模块的激活方式与经典导出类型的激活方式不同,因此模块无法使用 ImportingConstructor 导入您需要的服务。而是使用 Initialize 方法中的 ServiceLocator 来初始化它们。

这将起作用:

[ModuleExport("Module1.ModuleInit", typeof(Module1.ModuleInit))]
public class ModuleInit : IModule
{
    private readonly IRegionManager _regionManager;

    public void Initialize()
    {
        _regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();

        _regionManager.RegisterViewWithRegion(RegionNames.TopLeftRegion, () => _serviceLocator.GetInstance<MasterView>());
    }
}

我也认为这种行为有点令人不安。

【讨论】:

  • 感谢您的建议,但即使进行了这些更改,也不会调用 Initialize 方法。当在 MEFBootstrapper 之外创建(子)容器时,没有调用 ConfigureContainer 方法,该容器目录中的模块如何初始化?我知道我在这里遗漏了一些非常明显的东西。
  • “创造”是什么意思?它是在一个容器中组成还是只是实例化?
  • 我写的是针对子容器创建的。它们是使用以下内容创建的: this.appHost = new CompositionContainer(catalog, new ExportProvider[] { provider });
  • 如果你想从引导程序初始化这个模块,然后重写 ConfigureAggregate 方法并调用 this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(InitModule).Assembly));如果您的程序集位于目录中,请改用 DirectoryCatalog。如果要在 Booostrapper 之外初始化模块,请调用 ServiceLocator.Current.GetInstance() 来组合模块。但是,如果这个高跷不能解决您的问题,您能否提供一个示例项目,以便我可以重现您的问题并帮助您解决这个问题?
  • 示例 zip 的链接:skydrive.live.com/… 看看您是否可以获得第一个会话实例的容器来实际加载 Module1 和 Module2 并显示它们。
【解决方案3】:

我遇到了同样的问题,我的模块 Initialize() 方法没有被调用...我意识到我已经在我的 Initialize 方法上遗漏了“覆盖”关键字,该关键字在 Module 基类中声明为虚拟,我的所有模块继承自...添加了“覆盖”并且它起作用了!

【讨论】:

    猜你喜欢
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 2020-08-18
    • 2010-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多