Вопрос по c#, appdomain – Загрузка сборки массива байтов

7

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

public static void Main() 
{
    PermissionSet permissions = new PermissionSet(PermissionState.None);
    AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory };
    AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions);

    Byte[] primary = File.ReadAllBytes("Primary.dll_");
    Byte[] dependency = File.ReadAllBytes("Dependency.dll_");

    // Crashes here saying it can't find the file.
    friendlyDomain.Load(dependency);

    AppDomain.Unload(friendlyDomain);

    Console.WriteLine("Stand successful");
    Console.ReadLine();
}

Я создал две фиктивные библиотеки и переименовал их расширение в.dll_» намеренно, чтобы система нене сможет найти физические файлы. И то и другоеprimary а такжеdependency заполните правильно, но когда я пытаюсь позвонитьAppDomain.Load Метод с двоичными данными, он возвращается с:

Could not load file or assembly 'Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Зачем искать файл в системе?

ОБНОВИТЬ

Это, с другой стороны, кажется, работает:

public class Program {
    public static void Main() {
        PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted);
        AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory };
        AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions);

        Byte[] primary = File.ReadAllBytes("Primary.dll_");
        Byte[] dependency = File.ReadAllBytes("Dependency.dll_");

        // Crashes here saying it can't find the file.
        // friendlyDomain.Load(primary);

        Stage stage = (Stage)friendlyDomain.CreateInstanceAndUnwrap(typeof(Stage).Assembly.FullName, typeof(Stage).FullName);
        stage.LoadAssembly(dependency);

        Console.WriteLine("Stand successful");
        Console.ReadLine();
    }

}

public class Stage : MarshalByRefObject {
    public void LoadAssembly(Byte[] data) {
        Assembly.Load(data);
    }
}

Таким образом, кажется, есть разница междуAppDomain.Load а также .Assembly.Load

Есть ли в Dependency DLL какие-либо зависимости, которые неВозможно, это скопировано? Chris Mantle
Основное зависит от зависимости. Зависимость не имеет (не CLR) зависимостей, хотя. Похоже, время выполнения не должнохотя поискать файл для начала sircodesalot

Ваш Ответ

3   ответа
0

FusionLogViewer вы можете увидеть более подробную информацию о конкретной проблеме, с которой CLR сталкивается при загрузке сборки ... она может показать вам, в каких местах она 'пытается дать вам подсказку и т. д.

http://msdn.microsoft.com/en-us/library/e74a18c4(v=vs.71).aspxhttp://www.shujaat.net/2012/04/fusion-log-viewer-fuslogvw-for-assembly.html

Вы также можете обрабатывать события AssemblyLoad / AssemblyResolve / ResourceResolve на вашемAppDomain в вашем коде, чтобы проследить последовательность.

http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx

Это удобный пример, который использует пользовательский шаг MSBuild для встраивания любых зависимых от проекта сборок как ресурсов в вашу программу EXE, а затем используетAssemblyResolve загрузить их изResourceStream (делаетAssembly.Load() в массиве byte []).

http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application
Primary зависит отDependency, хоть. загрузкаDependency не должен»не вызывает никаких проблем, и на самом деле я узнал выше, что с помощьюAssembly.Load вроде нормально работает, покаAppDomain.Load не. sircodesalot
It can show you which locations it's trying to probe, Тот'это просто, это не должноэто похоже на Я'Я уже указал двоичный файл, поэтому нет никаких причин, чтобы он выходил и снова загружал его из файловой системы. sircodesalot
4

официальный исходный код если ты хочешь).

На странице MSDN дляМетод AppDomain.Load (байт []) Замечено, что этот метод загружает сборку в текущем домене приложения:

Этот метод следует использовать только для загрузки сборки в текущий домен приложения. Этот метод предоставляется для удобства тех, кто взаимодействует, которые не могут вызвать статический метод Assembly.Load. Чтобы загрузить сборки в другие домены приложений, используйте метод, например CreateInstanceAndUnwrap.

линия:

friendlyDomain.Load(dependency);

ведет себя точно так же с:

Assembly.Load(dependency);

Причина, по которой это работает в вашем обновленном примере кода, заключается в том, чтоStage объект на самом деле вызываетAssembly.Load внутриребенок AppDomain.

Примечание. Этот ответ дополняет ответы Ханса Пассанта и Колинсмит.

В конечном итоге я решил сохранить сборки во временную папку на диске, а затем установитьAppDomain база для этой папки. Я могу быть сумасшедшим, но я клянусь, кажется,AppDomain.Load все равно проверит диск на физическое присутствие сборки, тогда какAssembly.Load не. На самом деле, в моей текущей реализации я просто передаю полное имя сборки вfriendlyDomain.Load и он извлекает его изApplicationBase (как и ожидалось). Но почему бы неБрать массив байтов без проверки мне не под силу. sircodesalot
Это место. Я проверил источник. Jonathan Mitchell
10

зависимость» Вы загружены, чтобы быть подходящей сборкой, когда она ищет сборку, которая "первичный» необходимо. Проблема, связанная с "загрузка контекста "нетt для сборок, загруженных вот так. Это сделано намеренно, CLR не может гарантировать, что DLL Hell выигралаЭто не проблема, так как он не знает, откуда пришла сборка. Так как вы открыли дверь в DLL Hell, вы также должны избегать ада самостоятельно.

Вы'Вам нужно будет реализовать событие AppDomain.AssemblyResolve. Это будет срабатывать, когда CLR не может найти "зависимость», вы можете вернуть сборку, полученную из Assembly.Load (byte []). Однако вам придется делать это последовательно, когда он запускается более одного раза для одной и той же сборки, другими словами, возвращать одну и ту же сборку, или вы 'У меня будет больше проблем, вызванных идентификацией типа .NET. Производить трудно понять исключения "Можно'T Foo для Foo " стиль.

Есть и другие проблемы, это довольно неэффективно. Виртуальная память для сборки не может быть сохранена файлом на диске, поэтому она поддерживается файлом подкачки. Что увеличивает размер коммита для вашего процесса.

Конечно, лучше этого не делать.

Отмечая ваши советы по поводу файла подкачки, я решил создать временную папку / копию сборок на диске, а затем использоватьfriendlyDomain.Load (передавая полное имя сборки) и загрузите его с самого диска. Спасибо за предложение. sircodesalot
Это нене имеет ничего общего с Assembly.Load. Когда вы используете AssemblyResolve, CLR говорит:Мне нужно это" а ты говоришьвот", Таким образом, CLR знает, что он получил. Ваш оригинальный подход былВот что то и CLR говорит "понятия не имею, что это такое. Hans Passant
Я следую за тобойповторяю, но просто переключая методы, кажется, работает. Мне никогда не приходилось пользоватьсяAssemblyResolve потому что CLR принял это, когда оно пришло.Assembly.Load sircodesalot
ПочемуAssembly.Load кажется, позволяют это, в то время какAppDomain.Load не? Кроме того, хорошее замечание по размеру коммита. sircodesalot

Похожие вопросы