C# AppDomain 无法加载 DLL

Posted

技术标签:

【中文标题】C# AppDomain 无法加载 DLL【英文标题】:C# AppDomain can't load DLL 【发布时间】:2016-07-21 13:52:27 【问题描述】:

我正在尝试构建一个热插拔插件系统,用户可以在其中动态加载和卸载 dll。核心应用程序必须尽可能少地重新启动,因此我将尽可能多的功能转移到外部库。根据我的研究,我需要创建第二个 AppDomain 并将 DLL 加载到其中,然后将参数等传递给它以运行它。目前,我相信我的大部分程序都在工作,但是在从 CreateInstance 调用对象上的 AppDomain.Unwrap() 函数时遇到错误。错误如下:

System.InvalidCastException: Unable to cast transparent proxy to type 'Program1.Loader'.

这是加载代码:

try 
    unload(dom,out loader,true);
    dom=null;
    AppDomainSetup dms = new AppDomainSetup();
    dms.ConfigurationFile=Environment.CurrentDirectory+Path.DirectorySeparatorChar+"Program1.exe.config";
    dms.ApplicationBase=Environment.CurrentDirectory+Path.DirectorySeparatorChar+"Plugins";
    Evidence ev = AppDomain.CurrentDomain.Evidence;
    dom=AppDomain.CreateDomain("PluginManager",ev,dms);
    AssemblyName an = AssemblyName.GetAssemblyName(Environment.CurrentDirectory+"\\Plugins\\PluginManager.dll");

    ObjectHandle obj = dom.CreateInstance(an.FullName,"PluginManager.PluginManager");
    loader = (Loader)obj.Unwrap();
    loader.LoadAssembly(@"PluginManager.dll");

    if(!suppressOutput)
      Console.WriteLine("Reload successful.");
  
  catch(Exception e) 
    unload(dom,out loader,true);
    loader=null;
    Console.WriteLine("PluginManager failed loading. Enter \"reload\" to try again.\n");
    Console.Write(e+"\n\n");
  

这一行是引发错误的地方:

loader = (Loader)obj.Unwrap();

外部 DLL 中几乎没有代码,因为这是概念验证。如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PluginManager 
  public class PluginManager:MarshalByRefObject 
    public void run(string comm) 
      Console.WriteLine(comm);
    
  

编辑:这是加载器类的代码。

  class Loader:MarshalByRefObject 
    private Assembly _assembly;

    public override object InitializeLifetimeService() 
      return null;
    

    public void LoadAssembly(string path) 
      _assembly=Assembly.Load(AssemblyName.GetAssemblyName(path));
    

    public object ExecuteStaticMethod(string typeName,string methodName,params object[] parameters) 
      Type type = _assembly.GetType(typeName);
      MethodInfo method = type.GetMethod(methodName,BindingFlags.Static|BindingFlags.Public);
      return method.Invoke(null,parameters);
    
  

【问题讨论】:

【参考方案1】:

您似乎正试图在AppDomain 中创建PluginManager 类型的对象,然后将其代理转换为Loader 类型(您的代码示例中缺少该类型)。

问题出在以下几行:

ObjectHandle obj = dom.CreateInstance(an.FullName,"PluginManager.PluginManager");
loader = (Loader)obj.Unwrap();

如果您创建 Loader 的实例而不是 PluginManager - 或 - 强制转换为 PluginManager 而不是 Loader,它将起作用。我的猜测是前者:

ObjectHandle obj = dom.CreateInstance(an.FullName,"LoaderNamespace.Loader");

(将LoaderNamespace替换为真实的。)

【讨论】:

我已更新代码以包含加载程序演员表。你能用一些代码解释你的答案吗?我不确定你想让我做什么。 感谢编辑!但是Loader在主程序中。 CreateInstance 在尝试从 dll 加载时不会失败吗? 但是你不尝试加载Loader,你尝试加载PluginManager。那就是问题所在。这就是您传递给 AppDomain.CreateInstance 的内容。 是的,但 PluginManager 是我需要从 dll 加载的类。加载器在主程序中。如果我执行您建议的交换,我会收到预期的错误,指出该 DLL 中不存在类加载器。

以上是关于C# AppDomain 无法加载 DLL的主要内容,如果未能解决你的问题,请参考以下文章

C# 在 appdomain 调用方法中加载 dll,而不会再次加载 dll

消息泵和 AppDomain

将 DLL 加载到具有已知唯一公共接口的单独 AppDomain 中

AppDomain 详解二-C#中动态加载和卸载DLL

无法在新的 AppDomain 中创建 UserControl

无法在新的 appDomain 中加载程序集