将程序集加载到临时应用程序域
我见过几个类似的问题,但没有解决我的问题。场景是 - 我有外部存储器中的几个DLL,我需要获得关于它们的信息(Assembly版本和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异常说“无法加载文件或程序......”
我明白为什么它正在发生,但我不知道如何来解决此。任务似乎很简单:
- 加载文件,
- 阅读它的版本,
- 忘掉它。
上面的逻辑没有什么复杂的。看起来像运行时需求过于复杂。有谁知道我怎么能使它工作?
任务看起来并不平凡。 AppDomain.Load方法不打算以这种方式使用它。
System.AppDomain类的Load方法可以加载程序集,但主要用于COM互操作性。它不应该用于将程序集加载到除调用它的应用程序域之外的应用程序域中。
我看到了两个解决方案,以你的情况:
简单方法。将汇编字节数组写入临时文件,并通过FileVersionInfo.GetVersionInfo读取其
FileVersion
和ProductVersion
。在大多数情况下,这些值应与AssemblyVersion
和AssemblyInformalVersion
中的值相同。使用
AppDomain
的正确方法。应用程序域的问题在于,您要加载的程序集应该从该域内部加载,而不是在外部加载。
要做到这一点,你需要创建一个包含所有必要的逻辑特殊类和类,应参照被编组(从MarshalByRef类继承它)。
然后,在创建新域后,您应该将该类加载到新创建的域中并将其解包。你可以用CreateInstanceAndUnwrap方法做到这一点。
这个类将生活在另一个领域,并给它的方法和属性的所有呼叫都将被整理到该域,所以你可以用你的逻辑来加载组件和阅读必要的信息。或者在其他域中做任何其他的东西。
完成后,您可以并应该卸载该域。
不要忘记,最初的应用程序域是完全空的,所以当你创建任何类的实例或加载额外的程序集时.net应该解析并加载所有相关的程序集到该域中。有时系统无法自动执行此操作,但在这种情况下,您可以通过订阅新域的AssemblyResolve事件来帮助系统执行此操作。
感谢您的回复。如果“AppDomain.Load方法不打算以这种方式使用它。”那么我不想“误用”它。我会尝试临时下载解决方案,并让你知道是否成功。我有一个控制DLL创建(他们是在网站上创建和编译),所以我应该能够设置FileVerison,所以它将等于AssemblyVersion。 – MajkeloDev
我结束了steve16351的解决方案http://stackoverflow.com/questions/26106431/loading-byte-array-assembly-into-new-appdomain-throws-a-filenotfound-exception/26107788?noredirect=1#comment72198604_26107788 – MajkeloDev
需要更多的堆栈跟踪(总是提供完整的信息)有可能在加载任何传入的字节数组之前,依赖程序集无法加载。您应从“应用程序域”复制某些属性默认,如探测路径。你还想使用'ReflectionOnlyLoad',它不会试图解决所有问题。 –
@ escape-llc AppDomain不公开“ReflectionOnlyLoad”函数。稍后我会用StackTrace更新问题。谢谢。 – MajkeloDev