我有一个在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
文档中有一条注释:
此方法应仅用于将程序集加载到当前应用程序域中。
是的,它应该用于那个,但是......
如果当前
AppDomain
对象表示应用程序域A,并且从应用程序域BLoad
调用该方法,则程序集将加载到两个应用程序域中。
我可以忍受这一点。如果程序集将被加载到两个应用程序域中,对我来说没有问题(因为我实际上将它加载到默认应用程序域中)。
我可以看到该程序集已加载到新的应用程序域中。有点儿。
var assemblies = newAppDomain.GetAssemblies().Select(a => a.GetName().Name);
Console.WriteLine(string.Join("\r\n", assemblies));
这给了我:
mscorlib
MyAssembly
但是尝试实例化类总是会导致 a 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
中,而无需将调用程序集从文件加载到该应用程序域中?实际上,没有任何文件系统访问我的应用程序目录?