当子目录中的 dll 时,MEF 找不到模块的视图
MEF can't find module's views when dll in subdirectory
我尝试使用 Prism 和 MEF 制作一个小应用程序以了解其工作原理。我陷入了一个相当令人沮丧的问题。
我想在我的基本应用程序目录中有一个 "Modules" 子目录,我将所有模块的 dll 复制为 post 构建事件。
这些模块是带有 View 和 ViewModel 的 MVVM 应用程序。
我的问题是:当我在主应用程序目录中复制模块的 dll 时,视图显示在 shell 中,但是当我的模块在子目录中时,没有显示。
我的模块及其部分已找到,但根据 fuslogvw 无法找到视图:
* Assembly Binder Log Entry (27/11/2015 @ 16:45:28) *
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = ModuleB.resources, Version=1.0.0.0, Culture=en-US, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = HelloWorld.vshost.exe
Calling assembly : ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: All probing URLs attempted and failed.
我不知道为什么 MEF 在 "modules\en-US\" 中查找,我认为这可能是它找不到任何视图的原因,但我找不到其他方式的说明。
我的引导程序:
public class Bootstrapper : MefBootstrapper
{
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll");
this.AggregateCatalog.Catalogs.Add(catalog);
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<MainWindow>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (MainWindow)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
我的模块:
[ModuleExport(typeof(ModuleAModule))]
public class ModuleAModule : IModule
{
IRegionManager _regionManager;
[ImportingConstructor]
public ModuleAModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion(RegionNames.RightRegion, typeof(ViewA));
}
}
我的看法:
/// <summary>
/// Interaction logic for ViewA.xaml
/// </summary>
[Export]
public partial class ViewA : UserControl
{
public ViewA()
{
InitializeComponent();
}
}
我的视图模型:
[Export]
public class ViewAViewModel : BindableBase
{
private string _title = "Module A";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
}
有人吗?
编辑:
以下是适合想看一看的解决方案:HelloWorldPrismMef
编辑 2 :
调查还在继续,我发现了一个非常好用的mefx!所以我的问题似乎是:
[Part] ModuleA.ModuleAModule from: DirectoryCatalog (Path="Modules")
[Primary Rejection]
[Export] ModuleA.ModuleAModule (ContractName="Prism.Modularity.IModule")
[Import] ModuleA.ModuleAModule..ctor (Parameter="regionManager", ContractName="Prism.Regions.IRegionManager")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint contract name
ContractName Prism.Regions.IRegionManager
RequiredTypeIdentity Prism.Regions.IRegionManager n'a été trouvée.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
这是否意味着我需要导出 IRegionManager class?
您 posted 的日志是关于尝试加载资源 .dll
,MEF 永远不会加载的东西(资源 .dll
s 用于存储应用程序资源信息,就像国际化的字符串)。您应该查找未提及资源 .dll
s.
的错误
此外,在我看来您正在尝试编辑 the Prism Library HelloWorld example from GitHub。这个特定示例与 ModuleA 紧密耦合(我的意思是 ModuleA 在 HelloWorld[= 中用作项目依赖项102=]),据我所知,您不能简单地将 ModuleA.dll
从主文件夹移动到 modules
文件夹并期望它能正常工作。
我的建议是添加一个新项目,将其设置为输出到模块文件夹并查看是否加载(单独保留 ModuleA 项目)。或者您可以从 HelloWorld 项目中删除引用并使用 post 构建事件.
现在关于从目录加载模块,以我的拙见,你把它复杂化了。您只需要
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(@".\Modules"));
或者假设您有一个约定,为模块文件名指定类似于 AppName.Modules.[ModuleNameHere].dll
的模式(例如:AppName.Modules.LoginModule.dll
您可以使用类似这样的方式加载模块
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(@".\Modules", "AppName.Modules.*Module.dll"));
虽然这里似乎不是这种情况,但如果您尝试从被视为不可信的区域加载模块,默认的安全策略是忽略该模块。如果您尝试通过 Windows Share 等网络连接 运行 应用程序,就会发生这种情况。对于这种情况,您需要将这些说明添加到 App.config
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
这些应该添加到 <startup />
部分之后。
希望对您有所帮助。
编辑:
Does that mean that I need to Export a IRegionManager class ?
不,那只是抱怨,因为 mefx 没有加载导出它的程序集(Prism.Wpf.dll 我认为它被调用)。
我个人认为 mefx.exe 很麻烦;我更喜欢 GUI version
现在关于您的代码,我查看了 GitHub 存储库并进行了一些更改,但没有那么多(与 ModuleC 的引用有一些问题,所以我必须删除并重新添加 Prism.Mef & company):
- 已从 基础设施 项目
中删除了 PostBuildEvent
更改了模块项目中的 PostBuildEvent。这需要一些解释:
- 所有宏都附加了目录分隔符“\”,因此您无需添加它(我指的是 $(OutDir)\Modules => $(OutDir)模块).
- COPY/XCOPY 要求目标路径以分隔符结尾,否则目标路径将被解释为目标目录( $(OutDir)Modules => *$ (OutDir)模块*).
- 目标目录需要存在(所以第一个命令应该是 MKDIR)
我还评论(以 REM 开头的行是评论)复制 .pdb
的命令,因为我认为不需要它并添加了 /z 标记为 XCOPY.
添加了 ILoggerFacade 作为依赖项以演示模块实际加载。如果您 运行 来自 Visual Studio 调试器的应用程序,您将在调试 window.
中看到一些消息
- 在
App.config
中添加了 <loadFromRemoteSources enabled="true" />
=> <configuration />
=> <runtime />
这样我就可以 运行 在存储项目的挂载分区上安装应用程序.
所有这些都在 PR 中。
至于为什么不自动显示区域的浏览量,我还不能说。我会在空闲时间继续调查,但你问 Brian Lagunas 可能会更好,因为他是 Prism.
的开发者之一
编辑 2:
当我查看 Brian Lagunas 的个人资料时,我看到他回答了这个 幸运地解决了这个问题。
还将添加一个 PR 到 GitHub.
我尝试使用 Prism 和 MEF 制作一个小应用程序以了解其工作原理。我陷入了一个相当令人沮丧的问题。 我想在我的基本应用程序目录中有一个 "Modules" 子目录,我将所有模块的 dll 复制为 post 构建事件。 这些模块是带有 View 和 ViewModel 的 MVVM 应用程序。
我的问题是:当我在主应用程序目录中复制模块的 dll 时,视图显示在 shell 中,但是当我的模块在子目录中时,没有显示。 我的模块及其部分已找到,但根据 fuslogvw 无法找到视图:
* Assembly Binder Log Entry (27/11/2015 @ 16:45:28) *
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = ModuleB.resources, Version=1.0.0.0, Culture=en-US, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = HelloWorld.vshost.exe
Calling assembly : ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Users\mouarf\Downloads\Prism-Samples-Wpf-master\Prism-Samples-Wpf-master\HelloWorld\HelloWorld\bin\Debug\HelloWorld.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/Users/mouarf/Prism/HelloWorld/bin/Debug/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.DLL.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources.EXE.
LOG: Attempting download of new URL file:///C:/USERS/Mouarf/PRISM/HELLOWORLD/BIN/DEBUG/MODULES/en-US/ModuleB.resources/ModuleB.resources.EXE.
LOG: All probing URLs attempted and failed.
我不知道为什么 MEF 在 "modules\en-US\" 中查找,我认为这可能是它找不到任何视图的原因,但我找不到其他方式的说明。
我的引导程序:
public class Bootstrapper : MefBootstrapper
{
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll");
this.AggregateCatalog.Catalogs.Add(catalog);
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<MainWindow>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (MainWindow)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
我的模块:
[ModuleExport(typeof(ModuleAModule))]
public class ModuleAModule : IModule
{
IRegionManager _regionManager;
[ImportingConstructor]
public ModuleAModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion(RegionNames.RightRegion, typeof(ViewA));
}
}
我的看法:
/// <summary>
/// Interaction logic for ViewA.xaml
/// </summary>
[Export]
public partial class ViewA : UserControl
{
public ViewA()
{
InitializeComponent();
}
}
我的视图模型:
[Export]
public class ViewAViewModel : BindableBase
{
private string _title = "Module A";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
}
有人吗?
编辑:
以下是适合想看一看的解决方案:HelloWorldPrismMef
编辑 2 :
调查还在继续,我发现了一个非常好用的mefx!所以我的问题似乎是:
[Part] ModuleA.ModuleAModule from: DirectoryCatalog (Path="Modules")
[Primary Rejection]
[Export] ModuleA.ModuleAModule (ContractName="Prism.Modularity.IModule")
[Import] ModuleA.ModuleAModule..ctor (Parameter="regionManager", ContractName="Prism.Regions.IRegionManager")
[Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint contract name
ContractName Prism.Regions.IRegionManager RequiredTypeIdentity Prism.Regions.IRegionManager n'a été trouvée.
at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
这是否意味着我需要导出 IRegionManager class?
您 posted 的日志是关于尝试加载资源 .dll
,MEF 永远不会加载的东西(资源 .dll
s 用于存储应用程序资源信息,就像国际化的字符串)。您应该查找未提及资源 .dll
s.
此外,在我看来您正在尝试编辑 the Prism Library HelloWorld example from GitHub。这个特定示例与 ModuleA 紧密耦合(我的意思是 ModuleA 在 HelloWorld[= 中用作项目依赖项102=]),据我所知,您不能简单地将 ModuleA.dll
从主文件夹移动到 modules
文件夹并期望它能正常工作。
我的建议是添加一个新项目,将其设置为输出到模块文件夹并查看是否加载(单独保留 ModuleA 项目)。或者您可以从 HelloWorld 项目中删除引用并使用 post 构建事件.
现在关于从目录加载模块,以我的拙见,你把它复杂化了。您只需要
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(@".\Modules"));
或者假设您有一个约定,为模块文件名指定类似于 AppName.Modules.[ModuleNameHere].dll
的模式(例如:AppName.Modules.LoginModule.dll
您可以使用类似这样的方式加载模块
AgregateCatalog.Catalogs.Add(new DirectoryCatalog(@".\Modules", "AppName.Modules.*Module.dll"));
虽然这里似乎不是这种情况,但如果您尝试从被视为不可信的区域加载模块,默认的安全策略是忽略该模块。如果您尝试通过 Windows Share 等网络连接 运行 应用程序,就会发生这种情况。对于这种情况,您需要将这些说明添加到 App.config
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
这些应该添加到 <startup />
部分之后。
希望对您有所帮助。
编辑:
Does that mean that I need to Export a IRegionManager class ?
不,那只是抱怨,因为 mefx 没有加载导出它的程序集(Prism.Wpf.dll 我认为它被调用)。
我个人认为 mefx.exe 很麻烦;我更喜欢 GUI version
现在关于您的代码,我查看了 GitHub 存储库并进行了一些更改,但没有那么多(与 ModuleC 的引用有一些问题,所以我必须删除并重新添加 Prism.Mef & company):
- 已从 基础设施 项目 中删除了 PostBuildEvent
更改了模块项目中的 PostBuildEvent。这需要一些解释:
- 所有宏都附加了目录分隔符“\”,因此您无需添加它(我指的是 $(OutDir)\Modules => $(OutDir)模块).
- COPY/XCOPY 要求目标路径以分隔符结尾,否则目标路径将被解释为目标目录( $(OutDir)Modules => *$ (OutDir)模块*).
- 目标目录需要存在(所以第一个命令应该是 MKDIR)
我还评论(以 REM 开头的行是评论)复制
.pdb
的命令,因为我认为不需要它并添加了 /z 标记为 XCOPY.添加了 ILoggerFacade 作为依赖项以演示模块实际加载。如果您 运行 来自 Visual Studio 调试器的应用程序,您将在调试 window.
中看到一些消息
- 在
App.config
中添加了<loadFromRemoteSources enabled="true" />
=><configuration />
=><runtime />
这样我就可以 运行 在存储项目的挂载分区上安装应用程序.
所有这些都在 PR 中。
至于为什么不自动显示区域的浏览量,我还不能说。我会在空闲时间继续调查,但你问 Brian Lagunas 可能会更好,因为他是 Prism.
的开发者之一编辑 2:
当我查看 Brian Lagunas 的个人资料时,我看到他回答了这个
还将添加一个 PR 到 GitHub.