在运行时切换DLL以使用不同版本是否可行?

7
我有一个应用程序,其中包含许多插件(MEF),这些插件连接到许多不同的I/O设备。大多数这些插件都有许多托管和非托管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)

有没有什么方法可以实现我的目标,或者我必须构建两个单独的应用程序版本?
编辑:我还应该说一下,没有必要同时加载这两个 DLL。只需使用一个参数启动应用程序,就可以加载其中一个 DLL。

2
尝试使用不同的“AppDomain”实例。 - Enigmativity
可能是在运行时更改.dll的重复问题。 - Abhishek
3个回答

5

实现这个目标的一种(复杂)方式是:

1. 使用FileSystemWatcher(FSW)监视文件夹

FSW检测程序集是否被更改或删除。

2. 将程序集加载到Reflection-Only Context

加载到此上下文中的程序集只能被检查!请确保程序集类型实现了PluginInterface,方法是获取程序集的类型并检查这些类型是否实现了PluginInterface。

3. 使用Shadow Copying将程序集加载到单独的AppDomain中

由于您只能卸载带有所有程序集的AppDomain,因此您需要在其自己的AppDomain中加载每个插件程序集。这样,您只需卸载插件的AppDomain即可。

请确保终止插件的所有进程/线程!

影子复制通过将程序集复制到临时路径来确保原始文件的更改。

4. 跟踪已加载的程序集

将成功加载的程序集路径放入列表中,这样更容易检测是否需要加载/重新加载程序集。

5. 处理FSW事件

检查哪个.dll被更改/删除以卸载程序集,或者如果检测到新程序集则加载它。

6. 转到步骤2


问候,Blackanges

影子复制是热交换MEF程序集的正确方法。 - plast1k
@plast1k 但是你仍然需要在单独的应用程序域中加载插件。影子复制会加载原始文件的“副本”,使您能够更改原始文件,但MEF不会加载更改后的原始文件。它仍然使用副本。 MEF无法卸载/重新加载单个程序集。只能卸载应用程序域中的所有程序集。 - er4zox
我同意,抱歉我主要是在指出其他答案没有讨论的内容。 - plast1k

1

0

也许你可以通过反射在运行时加载dll,就像这样:在C#中运行时加载DLL

但我怀疑它是否适用于更大的项目


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接