【发布时间】:2019-09-25 04:33:22
【问题描述】:
我有一个内存程序集 MyAssembly(类库),用于我的主程序集 MyApp.exe:
byte[] assemblyData = GetAssemblyDataFromSomewhere();
(对于测试,GetAssemblyDataFromSomewhere 方法可以对现有的程序集文件执行File.ReadAllBytes,但在我的真实应用程序中没有文件。)
MyAssembly 仅具有 .NET Framework 引用,不依赖于任何其他用户代码。
我可以将此程序集加载到当前(默认)AppDomain:
Assembly.Load(assemblyData);
// this works
var obj = Activator.CreateInstance("MyAssembly", "MyNamespace.MyType").Unwrap();
现在,我想将此程序集加载到不同的AppDomain 并在那里实例化该类。 MyNamespace.MyType 派生自 MarshalByRefObject,因此我可以跨应用程序域共享实例。
var newAppDomain = AppDomain.CreateDomain("DifferentAppDomain");
// this doesn't really work...
newAppDomain.Load(assemblyData);
// ...because this throws a FileNotFoundException
var obj = newAppDomain.CreateInstanceAndUnwrap("MyAssembly", "MyNamespace.MyType");
是的,我知道AppDomain.Load docs中有一条注释:
此方法应仅用于将程序集加载到当前应用程序域中。
是的,它应该用于那个,但是...
如果当前
AppDomain对象代表应用程序域A,并且从应用程序域B 调用Load方法,则程序集被加载到两个应用程序域.
我可以忍受。如果程序集将被加载到两个应用程序域中,对我来说没有问题(因为我实际上将它加载到默认应用程序域中)。
我可以看到该程序集已加载到新的应用程序域中。有点。
var assemblies = newAppDomain.GetAssemblies().Select(a => a.GetName().Name);
Console.WriteLine(string.Join("\r\n", assemblies));
这给了我:
mscorlib
MyAssembly
但是尝试实例化类总是会导致FileNotFoundException,因为 CLR 会尝试从文件加载程序集(尽管它已经加载,至少根据 AppDomain.GetAssemblies)。
我可以在MyApp.exe:
newAppDomain.AssemblyResolve += CustomResolver;
private static Assembly CustomResolver(object sender, ResolveEventArgs e)
{
byte[] assemblyData = GetAssemblyDataFromSomewhere();
return Assembly.Load(assemblyData);
}
这可行,但这会导致第二个应用程序域从文件加载调用程序集 (MyApp.exe)。发生这种情况是因为该应用程序域现在需要来自调用程序集的代码(CustomResolver 方法)。
我可以将应用程序域创建逻辑和事件处理程序移动到不同的程序集中,例如MyAppServices.dll,因此新的应用程序域将加载该程序集而不是 MyApp.exe。
但是,我想不惜一切代价避免文件系统访问我的应用程序目录:新的应用程序域不得从文件中加载任何用户程序集。
我也试过AppDomain.DefineDynamicAssembly,但也没有用,因为返回值的类型System.Reflection.Emit.AssemblyBuilder既不是MarshalByRefObject,也不是[Serializable]。
有没有办法将程序集从字节数组加载到非默认 AppDomain 而不将调用程序集从文件加载到该应用程序域?实际上,我的应用程序目录没有任何文件系统访问权限?
【问题讨论】:
-
"这可行,但这会导致第二个应用程序域从文件加载调用程序集 (MyApp.exe)。这是因为应用程序域需要代码(类型)形式程序集" ..."我想不惜一切代价避免这种情况:新的应用程序域不得从文件中加载任何用户程序集。" 那么,在某些时候你的第二个应用程序域需要以某种方式加载 MyApp.exe,不是吗?您自己是这么说的,因为您加载到第二个应用程序域中的一些汇编代码似乎需要来自 MyApp.exe 的类型。我的意思是,如果它需要来自其他程序集的类型,你希望它做什么......?
-
@elgonzo,
MyApp.exe文件很大,因为有很多嵌入式资源。它在启动时首先加载,是的,但我需要避免任何进一步的加载。MyAssembly没有引用MyApp.exe并且没有其他对我的程序集的引用。只有当我连接AssemblyResolve事件时才会发生这种情况 - 所以我不能这样做。 -
我是否正确理解您,AssemblyResolve 处理程序是在您的 MyApp.exe 中声明的方法(匿名或非匿名),从而将 MyApp.exe “拉”到第二个应用程序域中?
-
@elgonzo,正确。我稍微编辑了我的问题以使其更清楚。
-
我猜你需要从你的 MyApp.exe 中“提升”那个处理程序。要么将其作为 GetAssemblyDataFromSomewhere 返回的程序集的一部分(如果可行),要么只创建(还)另一个程序集(动态地在内存中或作为单独的 DLL,具体取决于您的要求)。有几种方法可以触发第二个应用程序域中的 AssemblyResolve 处理程序的事件订阅。从第一个应用程序域显式设置它,或者在第二个应用程序域中使用(静态?)方法或类似类型的方法,该方法将通过反射从第一个应用程序域调用...
标签: c# .net .net-assembly appdomain assembly-loading