简体   繁体   中英

C# AppDomain can't load DLL

I'm attempting to build a hot-swapable plugin system where the user can dynamically load and unload dll's. It's necessary that the core application restart as little as possible, so I'm moving as much of the functionality to external libraries instead. From what research I've figured out, I need to create a second AppDomain and load the DLL into that, then just pass along parameters and such to that to run it. Currently, I believe I have most of the program working, but I'm encountering an error when calling the AppDomain.Unwrap() function on the object from CreateInstance. The error is as follows:

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

Here is the loading code:

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");
  }

This line is where the error is thrown:

loader = (Loader)obj.Unwrap();

The external DLL has almost no code in it, since this is a proof of concept. It is as follows:

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);
    }
  }
}

Edit: Here's the code for the loader class.

  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);
    }
  }

It looks like you're trying to create an object of the type PluginManager in the AppDomain and then cast its proxy to the type Loader (which is missing from your code sample).

The problem is in these lines:

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

It would work if you either create an instance of Loader instead of PluginManager - or - cast to PluginManager instead of Loader . My guess is the former:

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

(Replace LoaderNamespace with the real one.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM