Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 应用程序使用的DLL的热卸载/重新加载_C# - Fatal编程技术网

C# 应用程序使用的DLL的热卸载/重新加载

C# 应用程序使用的DLL的热卸载/重新加载,c#,C#,我有一个应用程序,它加载一个DLL来执行处理的特定部分 Example : "Application.dll" loading "Process.dll" Process.dll在运行时使用反射动态加载,并且不在应用程序中引用 处理完成后,需要在服务器上重新编译DLL,然后重新加载。 为此,我需要释放它,否则我会收到以下消息: 无法将文件“Process.dll”复制到“Process.dll”。该进程无法访问文件“Process.dll”,因为另一进程正在使用该文件 所以问题是:如何以编程

我有一个应用程序,它加载一个DLL来执行处理的特定部分

Example : "Application.dll" loading "Process.dll" 
Process.dll在运行时使用反射动态加载,并且不在应用程序中引用

处理完成后,需要在服务器上重新编译DLL,然后重新加载。
为此,我需要释放它,否则我会收到以下消息: 无法将文件“Process.dll”复制到“Process.dll”。该进程无法访问文件“Process.dll”,因为另一进程正在使用该文件

所以问题是:如何以编程方式从我的应用程序中释放/释放/卸载
Process.dll
,然后再重新加载它。当然,关键是在不停止应用程序的情况下执行此操作

编辑1:

建议的解决方案如下所示:

AppDomain newDomain4Process = AppDomain.CreateDomain("newDomain4Process");
Assembly processLibrary = newDomain4Process.Load("Process.dll");
AppDomain.Unload(newDomain4Process);
我仍然存在的问题是,尽管我给出了正确的完整路径,但我得到了一个
FileNotFound异常。这个问题的答案也没有达到预期的效果

编辑2:

救了我的命,下面是代码:

class ProxyDomain : MarshalByRefObject
    {
        public Assembly GetAssembly(string AssemblyPath)
        {
            try
            {
                return Assembly.LoadFrom(AssemblyPath);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

   ProxyDomain pd = new ProxyDomain();
   Assembly a = pd.GetAssembly(FullDLLPath);
编辑3:
但是,我没有访问AppDomain并使用以前的解决方案卸载它。 当我使用经典的AppDomain创建方法时,我感受到了Alexei的警告:
AppDomain.Unload
“似乎”起作用,但程序集仍然被加载(模块视图)。
因此,在某种程度上我仍然存在问题,因为我无法真正有效地卸载DLL。

我已经有一段时间没有看到这一点了,但我相当确定您需要创建一个新的DLL,然后在其中加载DLL


原因是您无法自行卸载
程序集
,但您可以卸载包含
程序集

AppDomain
,一旦将程序集加载到
AppDomain
,则无法卸载该程序集。您必须处理
AppDomain
。如果您需要在应用程序中加载和卸载程序集,则需要生成一个新的
AppDomain
并加载程序集,然后在完成程序集后销毁
AppDomain

虽然您似乎根据您的编辑解决了问题,但这里有几条注释:

小心Process.dll中的对象“泄漏”到主AppDomain中。例如,抛出Process.dll中定义并在主AppDomain中捕获的自定义异常将强制将Process.dll加载到主AppDomain中。执行您感兴趣的操作后,检查主AppDomain中已加载程序集的列表


卸载AppDomain可能会失败,并且可能需要很长时间

正确,您无法从应用程序域“卸载”DLL。没错,一旦程序集位于应用程序域中,就无法从应用程序域卸载程序集。好吧。我的编辑正确吗?从技术上讲,这就足够了吗?顺便说一句,幕后发生了什么?AppDomains是独立的,但仍然可以在彼此之间“通信”程序集?@Mika:对不起,几年来都没有看过这个,所以不能对您的代码片段发表评论,除非说它看起来似乎有道理。@HansOlsson提供的链接无效EELP!我陷入了漏水的问题!伙计,这是个坏消息。模块视图显示该死的程序集仍在加载。我有什么办法可以强迫它退出吗?你不能强迫它退出-一旦它加载到特定的AppDomain中,它就会留在那里。您必须避免该程序集的类型跨越AppDomain边界。确保不返回该程序集中定义的任何对象。也就是说,若要从主程序集中返回实现接口的对象,则可能需要在主程序集中编写代理类并返回该类。预计将花费大量时间了解将程序集加载到新AppDomain的整个过程。关于编辑3。这让我想起了,现在我尝试它时,由于类似的问题,我放弃了,转而创建一个非常简单的包装器可执行文件,它将加载DLL,我的原始可执行文件通过COM接口与DLL通信。然后,每当我需要加载新版本的DLL时,我就关闭包装器可执行文件,因此我不需要担心AppDomains。这对我来说还行,因为性能并不是那么重要,所以让dll退出进程并没有影响我:)哥们哈哈。我要放弃了(至少现在是这样),因为已经两天了,我有一种陷入深渊的感觉。我的生活一直是痛苦的诅咒,因为我一直试图处理我所遇到的大量错误/问题,这些错误/问题似乎很难在合理的时间内解决,而且没有深入挖掘概念以真正理解我在做什么。目前,我要休息一段时间,回到以前的常规编码,因为我有一个项目要交付:-)小心权衡,AppDomains之间会发生封送(序列化)。您还可以做一件事来帮助减少过程中的停机时间:等待旧AppDomain完成任何任务,卸载旧AppDomain,复制新DLL,然后加载正在使用的新AppDomain。这将删除“无法复制文件…”错误,并允许您更改步骤顺序:复制新dll、加载新AppDomain并开始处理新请求、等待旧AppDomain完成旧请求、卸载旧AppDomain。所以现在您的停机时间为0。@StevensMiller我也尝试过同样的情况,只是我不想卸载DLL,我只是用新的pdb/mdb文件创建了一个新的DLL。我遇到了调试器在断点处不会随机中断等问题。你的想法听起来很有趣,你能详细说明一下吗?你是说这个“shell”DLL是C++,你的DLL是C?那么您正在托管DLL上使用LoadLibrary?你有什么问题吗