在新的应用程序域中加载程序集
Posted
技术标签:
【中文标题】在新的应用程序域中加载程序集【英文标题】:Load assembly in new appdomain 【发布时间】:2020-09-02 14:53:29 【问题描述】:我正在开发需要不同程序集的服务,但在编译时我们不知道哪些程序集。因此我想动态加载卸载不同的程序集。 我已经使用此代码进行加载,
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);
但是我发现程序集只能通过卸载appdomain来卸载。因此它需要在不同的可以卸载的应用程序域中运行。但我没有得到这个工作。我尝试了下面的代码,但它不起作用,因为 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);
【问题讨论】:
您真的想将 EXE 加载到新的应用程序域中吗?这闻起来不对 - 为什么是 exe? 可执行吗?也许你可以开始一个新的进程。 【参考方案1】:将cmets之后的答案更新为初始答案。
使用 Unwrap 获取实例访问权限的直接方法不起作用,因为反射方法返回有关代理对象的信息,而不是目标类型的底层实例。
要解决此限制,需要将“已知”类型的对象注入应用程序域,以便反射代码在应用程序域内工作。
代码:
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);
启动任务的例程:
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);
【讨论】:
谢谢,但它还没有工作。解包返回错误 System.Runtime.Serialization.SerializationException: '类型 'c' 在程序集 'a' 中未标记为可序列化。'我尝试继承 MarshalByRefObject 但 getType() 返回 MarshlByRefObject 并且找不到该方法。 您的应用是否可以要求所有“taskName.ClassName”都从特定接口继承?有了这个限制,就可以轻松解决问题。否则,将需要一些技巧。以上是关于在新的应用程序域中加载程序集的主要内容,如果未能解决你的问题,请参考以下文章