我正在使用MVF Light Messenger和SimpleIOC的WPF项目。该解决方案有几个项目提供了使用串行/ USB设备的实现,这些实现使用通用接口来抽象出各种设备的细节。
在应用程序启动时,解决方案在IOC中注册我们的依赖项:
Kernel.Container.Register<IMainWindow, MainWindow>(Lifestyle.Transient);
//more dependency registrations.
当MainWindow
加载时,我们会检测用户想要使用的设备并将其加载。但是,因为我们不想将应用程序紧密地耦合到设备实现,所以WPF应用程序中没有直接引用任何Device实现。加载设备时,我们使用Reflection来引入DLL并构造对象,并传回公共接口IDevice
。
加载DLL和构建设备的代码:
public static Assembly GetAssembly(string dll)
{
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
var path = Uri.UnescapeDataString(uri.Path);
//Load the assembly from the specified path.
var theDirectory = Path.GetDirectoryName(path);
var strTempAssmbPath = string.Format(@"{0}\Devices\{1}", theDirectory, dll);
var theDll = Assembly.LoadFile(strTempAssmbPath);
return theDll;
}
//Actual code that gets the assembly and loads the IDevice
var assembly = GetAssembly("MyDevice.dll");
(IDevice)Activator.CreateInstance(assembly.GetType(type), ConstructorConstraint);
每个设备使用静态MessageBus(对我们的Messaging库的直接项目引用)在设备上发生事件时将消息发送回应用程序(同样,允许从WPF应用程序中抽象出设备实现)。这是我们的MessageBus实现:
public static class MessageBus
{
public static void Send<T>(T message)
{
Messenger.Default.Send(message);
}
public static void Receive<T>(object subscriber, Action<T> action) where T : MessageBase
{
Messenger.Default.Register(subscriber, action);
}
}
通过调试器运行应用程序时,这一切都很好,一切都按预期工作。但是,在通过构建过程构建应用程序并打包安装程序,然后在我们的QA计算机上安装之后,WPF应用程序将正常运行,正确加载设备,但{设备实现发送的消息未被{正在运行的应用程序中的{1}}。
我们现在的运行理论是因为设备是在运行时加载的,所以它们没有得到与Messaging库相同的引用(缺少Messaging DLL或者设备dll中的引用不一样)作为WPF应用程序中的参考)。我们正在尝试将Messaging DLL复制到Devices文件夹中并获得一些混合结果。
为什么我们的应用程序在构建和打包应用程序以供发布之后,我们的应用程序收到的消息是否没有,但它在调试器中有效吗?
答案 0 :(得分:0)
解决方案非常难以捉摸,并没有真正解释这种行为,但我们能够解决问题。
基本上,我们的构建过程使用ILMerge的开源版本,它将依赖项合并到输出可执行文件中。作为该过程的一部分,ILMerge的版本存在将程序集合并到WPF可执行文件中的问题,这些可执行文件不是WPF项目本身的嵌入式资源。要解决该问题,我们必须在WPF项目上安装一个MSBuild任务,该任务嵌入所有引用,以便ILMerge进程可以正确合并它们。例如:https://gist.github.com/thoemmi/3724333
这里的事情开始变得有些奇怪。我们Messaging
的{{1}}项目是WPF项目中的直接引用,并且由我们的构建过程嵌入和合并。我们的设备DLL无法从构建输出中解析合并在程序集中的那些引用。
为了让事情顺利进行,我们修改了构建过程,将MessageBus
DLL输出到与应用程序可执行文件相同的目录中,一切都按预期工作。
这不是我们希望的优雅解决方案,但它确实解决了我们的问题。
如果有人想出一个能够解决问题的更好答案,我会很乐意将其作为答案进行测试。