Как загрузить сборку из байтового массива в не используемый по умолчанию домен приложений без доступа к каталогу приложения? - PullRequest
0 голосов
/ 07 мая 2019

У меня есть сборка в памяти в формате COFF, которая используется в моей основной сборке 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 , а метод Load вызывается из домена приложения B ,сборка загружается в оба домена приложения.

Я могу жить с этим.Для меня нет проблем, если сборка будет загружена в оба домена приложения (потому что я все равно загружаю ее в домен приложения по умолчанию).

Я вижу, что сборка загружена в новый домен приложения.Вид.

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].

IsЕсть ли способ загрузить сборку из байтового массива в нестандартный AppDomain без загрузки вызывающей сборки из файла в этот домен приложения?На самом деле, без какой-либо файловой системы доступ к каталогу моего приложения?

...