是否可以在运行时切换DLL以便使用不同的版本?
我有一个应用程序,其中包含许多连接到许多不同I / O设备的插件(MEF)。 这些插件中的大多数都有许多托管和非托管dll。
一家制造商最近发布了新固件和新驱动程序。 API保持不变。
我认为我可以将两个dll版本包含在单独的资源文件夹中,并在应用程序启动时将所需的集复制到输出文件夹中。
( 我想我可以制作插件的第二个副本并找出加载正确的插件的方法,但我认为复制DLL可能更容易 – 特别是考虑到插件代码没有改变 )
这不起作用。
static MyClass() // static constructor { // required version? if (envvar.Equals("4") ) { path = "ver4.1.1"; } else { path = "ver2.5.1"; } // location of drivers path = Path.Combine("./Prj/QX", path); string[] files = Directory.GetFiles(path); // Copy the files and overwrite destination files if they already exist. foreach (string s in files) { string fileName = Path.GetFileName(s); string destFile = Path.Combine(".", fileName); File.Copy(s, destFile, true); } // force load of assemby Assembly assy = LoadWithoutCache("driver.dll"); string fn = assy.FullName; } static Assembly LoadWithoutCache(string path) { using (var fs = new FileStream(path, FileMode.Open)) { var rawAssembly = new byte[fs.Length]; fs.Read(rawAssembly, 0, rawAssembly.Length); return Assembly.Load(rawAssembly); } }
错误消息表明原始DLL已加载或应该已加载但不能。
Could not load file or assembly 'driver, Version=1.5.77, Culture=neutral, PublicKeyToken=983247934' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
有没有办法实现我的目标,还是我必须构建我的应用程序的2个单独版本?
编辑我还应该说,没有必要同时加载两个DLL。 用一个参数启动应用程序就足够了,这个参数会导致加载一个或另一个DLL。
实现这一目标的一种(复杂)方法是:
1.使用FileSystemWatcher(FSW)观看文件夹
FSW检测组件是否被更改或删除。
2.将程序集加载到仅reflection上下文中
加载到此上下文中的程序集只能被检查! 通过获取程序集的类型并检查类型是否实现PluginInterface,确保程序集类型实现PluginInterface。
3.使用卷影复制将程序集加载到单独的AppDomain中
由于您只能使用其所有程序集卸载AppDomain,因此您需要在其自己的AppDomain中加载每个插件程序集。 这样就可以卸载插件的AppDomain。
一定要终止插件的所有进程/线程!
卷影复制通过将程序集复制到临时路径来确保更改原始文件。
4.跟踪加载的组件
将成功加载的程序集的路径放入列表中。 这样可以更容易地检测assembly是否需要加载/重新加载。
5.处理FSW事件
检查更改/删除哪个.dll以卸载程序集,或者检测到新程序集加载它。
6.转到第2步
问候,Blackanges
你可以用几种方式做到这一点。 一种可能性是使用托管可扩展性框架(MEF) 。 您甚至可以监视dll所在的文件夹,并在新版本可用时立即加载新版本。
另一种可能性是您可以使用reflection在运行时动态加载所需的dll。
也许你可以通过这样的reflection在运行时加载你的dll: 在C#中运行时加载DLL
但我怀疑它是否适用于更大的项目