将程序集加载到临时AppDomain

时间:2017-02-28 13:36:38

标签: c# .net .net-assembly appdomain

我见过几个相似的问题,但没有一个解决我的问题。场景是 - 我在外部存储中有几个DLL,我需要获取有关它们的信息(程序集版本和AssemblyInformationalVersion是特定的)。我开始使用以下代码:

List<byte[]> assemblies = _client.DownloadAllAssemblies();
foreach(var assemblyBytes in assemblies)
{
    var assembly = Assembly.ReflectionOnlyLoad(assemblyBytes);
    var assemblyName = assembly.GetName();
    ... // read version from assembly name
}

以上代码只能运行一次。如果我单击一个按钮来刷新视图 - 它会抛出异常,表示程序集已经加载并且无法重新加载它。然后我读到我应该创建临时域并将程序集加载到其中,以便我可以在完成后卸载AppDomain。我尝试了以下代码:

List<byte[]> assemblies = _client.DownloadAllAssemblies();
var tempDomain = AppDomain.Create("TemporaryDomain");
foreach(var assemblyBytes in assemblies)
{
    var assembly = tempDomain.Load(assemblyBytes);
    var assemblyName = assembly.GetName();
    ... // read version from assembly name
}
AppDomain.Unload(tempDomain);

上面的代码抛出FileNotFound异常说&#34;无法加载文件或程序集......&#34;

我理解为什么会这样,但我不知道如何解决这个问题。这项任务似乎非常简单:

  1. 加载文件,
  2. 阅读其版本
  3. 忘了它。
  4. 上述逻辑没有什么复杂的。看起来像运行时要求过于复杂。有谁知道我怎么能让它发挥作用?

1 个答案:

答案 0 :(得分:2)

任务似乎并非微不足道。 AppDomain.Load方法不打算以这种方式使用它。

  

Load类的System.AppDomain方法可以加载程序集,但主要用于COM互操作性。它不应该用于将程序集加载到应用程序域以外的应用程序域中。

我看到了两种解决方案:

  1. 简单的方法。将汇编字节数组写入临时文件,并通过FileVersionInfo.GetVersionInfo读取其FileVersionProductVersion。在大多数情况下,这些值应与AssemblyVersionAssemblyInformalVersion中的值相同。

  2. 使用AppDomain更正方式。 app域的问题是,您要加载的程序集应该从该域内部加载,而不是从外部加载。

  3. 要实现这一点,您需要创建包含所有必要逻辑的特殊类,并且该类应该通过引用进行编组(从MarshalByRef类继承)。

    然后,在创建新域之后,您应该在新创建的域中加载该类并将其解包。您可以使用CreateInstanceAndUnwrap方法执行此操作。

    此类将存在于另一个域中,并且对其方法和属性的所有调用都将被编组到该域,因此您可以使用逻辑来加载程序集并读取必要的信息。或者在其他领域内做任何其他事情。

    完成后,您可以并且应该卸载该域。

    不要忘记,最初app域是完全空的,因此当您创建任何类的实例或加载其他程序集时,.net应解析并将所有相关程序集加载到该域中。有时系统无法自动执行此操作,但在这种情况下,您可以通过订阅新域AssemblyResolve事件来帮助系统执行此操作。