简体   繁体   English

在新的应用程序域中加载程序集

[英]Load assembly in new appdomain

I'm working on a service which needs different assemblies, but at compile time we don't know which ones.我正在开发一个需要不同程序集的服务,但在编译时我们不知道哪些程序集。 Therefore I want to dynamically load an unload different assemblies.因此我想动态加载一个卸载不同的程序集。 I had the loading working with this code,我使用此代码进行加载,

static private void ExecuteAssemblyMethod(string taskName, string className, string method)
    {
        //load assembly in parent application domain, the assembly can not be unloaded.
        var task = Assembly.LoadFrom($"tasks\\{taskName}.exe");
        var myType = task.GetType($"{taskName}.{className}");
        MethodInfo myMethod = myType.GetMethod(method);
        object obj = Activator.CreateInstance(myType);
        myMethod.Invoke(obj, null);
    }

But I found out the assembly can only be unloaded by unloading the appdomain.但是我发现只能通过卸载 appdomain 来卸载程序集。 Therefore it needs to run in a different appdomain which can be unloaded.因此,它需要在可以卸载的不同应用程序域中运行。 But I do not get this working.但我不明白这个工作。 I tried the code below, but it does not work because CreateInstanceFrom return type objecthandle and not object as I expected.我尝试了下面的代码,但它不起作用,因为 CreateInstanceFrom 返回类型 objecthandle 而不是我预期的 object。

        static private void ExecuteAssemblyMethodInAppDomain(string taskName, string className, string method)
    {
        //create child domain and load assembly within it. the appdomain can than be unloaded.
        var dom = AppDomain.CreateDomain("taskDomain");
        var task = dom.CreateInstanceFrom($"tasks\\{taskName}.exe", $"{ taskName}.{ className}");
        Type myType = task.GetType();
        MethodInfo myMethod = myType.GetMethod(method);
        myMethod.Invoke(task, null);
        AppDomain.Unload(dom);
    }

Updated the answer after the comments to the initial answer.在对初始答案的评论后更新了答案。

  1. The straightforward approach that uses Unwrap to gain access to the instance doesn't work because reflection methods return information about the proxy object, not by the underlying instance of the target type.使用 Unwrap 访问实例的直接方法不起作用,因为反射方法返回有关代理对象的信息,而不是目标类型的底层实例。

  2. To work around this limitation, one needs to inject an object of a 'known' type into the application domain, so that the reflection code works inside the app domain.要解决此限制,需要将“已知”类型的对象注入应用程序域,以便反射代码在应用程序域内工作。

Code:代码:

HelperAssembly -- contains a simple helper class Helper.cs HelperAssembly -- 包含一个简单的帮助类 Helper.cs

namespace HelperAssembly
{
  public class Helper : MarshalByRefObject
  {
    public void CreateAndRunPlugin(string assemblyName, string typeName, string methodName)
    {
      var task = AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(assemblyName, typeName);

      Type myType = task.GetType();
      MethodInfo myMethod = myType.GetMethod(methodName);
      myMethod.Invoke(task, null);

    }
  }
}

The routine that launches the task:启动任务的例程:

  private static void TestAppDomain(string taskName, string className, string methodName)
  {
    //create child domain and load assembly within it. the appdomain can than be unloaded.
    var dom = AppDomain.CreateDomain("taskDomain");
    try
    {
      var whelper = dom.CreateInstanceFrom("path\\to\\HelperAssembly.dll", "HelperAssembly.Helper");
      var helper = (Helper)whelper.Unwrap();
       helper.CreateAndRunPlugin($"path\\to\\{taskname}.exe", $"{taskName}.{className}", methodName);
      return;

    }
    finally
    {
      AppDomain.Unload(dom);
    }
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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