从另一个AppDomain封送程序集

3

在没有将该程序集加载到当前应用程序域中的情况下,是否可以从另一个应用程序域中持有一个程序集的引用?

我正在修复一个 Windows 服务中的内存泄漏问题,该服务动态生成程序集并运行动态生成的代码。问题在于,生成的程序集被加载到当前应用程序域中后无法卸载。

在其中一个 Windows 服务库中有一个具有以下签名的方法:

public Assembly CreateMethod(ObservableCollection<Field> sourceFields, Field destinationField)

这种方法创建汇编代码,并使用CSScript库的LoadMethod函数加载它:

result = CSScript.LoadMethod(scriptFunction.ToString());

后来,使用CreateMethod创建的此程序集引用用于在生成的程序集内运行函数。

public object Run(Field destinationField, ObservableCollection<LinkField> sourceLinkFields, DataRow mainRow, Assembly script) {

   ...

   var method = script.GetStaticMethodWithArgs("*.a" + Id.ToString().Replace("-", String.Empty), argumentTypes.ToArray());

   return method(arguments.ToArray());
}

我想知道是否可以将动态生成的程序集加载到另一个应用程序域中,并通过某种类型的代理运行它们,而无需将其加载到当前应用程序域中。
编辑:我想知道当程序集加载在另一个应用程序域中时,是否可以在一个应用程序域中使用Assembly类引用。从MSDN文档上看,他们展示了如何使用MarshalByRefObject。基本上,我试图避免更改CreateMethod函数的签名,但如果不可能,我可能需要将其更改为返回MarshalByRefObject。
更新:最终,我把对CSScript.LoadMethod的调用放在了另一个应用程序域中,我在那里保留了一个字典。然后我将CreateMethod的返回值从Assembly更改为Guid,然后我将这个Guid传递到Run调用中。现在,Run调用以Guid作为参数,而不是Assembly。在Run调用内部,我将Guid传递给另一个应用程序域,运行该方法,并通过继承MarshalByRefObject的类返回结果对象。

例如:请参考:https://dev59.com/gHVD5IYBdhLWcg3wGXlI - DeCaf
2个回答

1

这是AppDomain的主要特性之一!只需查看文档即可。


谢谢提供链接,我已经更新了问题并添加了一些额外的细节。我仍然不清楚是否需要将CreateMethod的签名更改为MarshalByRefObject,或者是否可以将返回类型保留为Assembly。 - dmck
为了帮助未来的他人,我想知道:您之前是否查看过“AppDomain”的文档? - John Saunders

1

如果您不想在主应用程序域中使用动态程序集,那么您必须将CreateMethod移动到另一个应用程序域中,因为一旦您拥有Assembly的实例,它就已经被加载了。换句话说,在另一个应用程序域中无法持有对程序集的引用,只能跨应用程序域调用该程序集。

如果不改变签名和大量代码,似乎您需要移动最少的内容:1)程序集创建和2)Run。然后,让Run的实现来传递结果。

至于CreateMethod,我认为您需要在另一个程序集中编写一个方法来“包装”CreateMethod并返回某种可以传递给Run的令牌。这几乎像是以某种方式更改签名...


谢谢,这是我最终采取的方法。我不得不更改CreateMethod和Run方法的签名,但仍然能够保持代码的原始设计。 - dmck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接