Как выгрузить сборку из основного AppDomain? - PullRequest
42 голосов
/ 23 сентября 2008

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

У меня есть следующий код:

var assembly = Assembly.LoadFrom( FilePathHere );

Мне нужно / я хочу иметь возможность выгрузить эту сборку, когда я закончу.

Спасибо за вашу помощь.

Ответы [ 8 ]

34 голосов
/ 23 сентября 2008

Для версий .net core 3.0 и новее:

Теперь вы можете выгружать сборки. Обратите внимание, что домены приложений больше не доступны в ядре .net. Вместо этого вы можете создать один или несколько AssemblyLoadContext, загрузить свои сборки через этот контекст, а затем выгрузить этот контекст. См. AssemblyLoadContext или это руководство, которое имитирует загрузку плагина и его выгрузку .

Для версий .net до .net core 3, включая netframework 4 и ниже

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

См. Объяснение Джейсона Зандера о Почему нет метода Assembly.Unload?

Если вы используете 3.5, вы можете использовать AddIn Framework, чтобы упростить управление / вызов в разные домены приложений (которые вы можете выгружать, выгружая все сборки). Если вы используете версии до этого, вам нужно самостоятельно создать новый домен приложения для его выгрузки.

21 голосов
/ 04 декабря 2015

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

var assembly = Assembly.LoadFrom( FilePathHere );

используйте это:

var assembly = Assembly.Load( File.ReadAllBytes(FilePathHere));

Это фактически загружает «Содержимое» файла сборки, а не сам файл. Это означает, что файл сборки НЕ помещен в файл! Теперь его можно копировать, удалять или обновлять, не закрывая приложение и не пытаясь использовать отдельный домен приложений или Marshaling!

PROS: Очень просто исправить с помощью 1 кода кода! CONS: Невозможно использовать AppDomain, Assembly.Location или Assembly.CodeBase.

Теперь вам просто нужно уничтожить все экземпляры, созданные в сборке. Например:

assembly = null;
15 голосов
/ 23 сентября 2008

Вы не можете выгрузить сборку, не выгружая весь AppDomain. Вот почему :

  1. Вы запускаете этот код в домене приложения. Это означает, что потенциально существуют сайты вызовов и стеки вызовов с адресами в них, которые ожидают продолжения работы.

  2. Допустим, вам удалось отследить все дескрипторы и ссылки на уже запущенный код в сборке. Предполагая, что вы не создали код, после того, как вы успешно освободили сборку, вы освободили только метаданные и IL. Код JIT все еще размещается в куче загрузчика домена приложения (методы JIT располагаются последовательно в буфере в порядке их вызова).

  3. Последняя проблема связана с кодом, который был загружен совместно используемым, иначе более формально известен как «нейтральный к домену» (проверка / совместное использование в инструменте ngen) В этом режиме код для сборки создается для выполнения из любого домена приложения (ничего сложного).

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

9 голосов
/ 20 марта 2009

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

4 голосов
/ 23 сентября 2008

Если вы хотите иметь временный код, который впоследствии можно будет выгружать, в зависимости от ваших потребностей класс DynamicMethod может делать то, что вы хотите. Это не дает тебе уроков.

1 голос
/ 28 ноября 2014

Я знаю, что он старый, но может кому-то помочь. Вы можете загрузить файл из потока и выпустить его. Это сработало для меня. Я нашел решение ЗДЕСЬ .

Надеюсь, это поможет.

1 голос
/ 24 декабря 2009

Вот хороший пример того, как скомпилировать и запустить dll во время выполнения, а затем выгрузить все ресурсы: http://www.west -wind.com / презентации / dynamicCode / DynamicCode.htm

0 голосов
/ 07 марта 2018

В качестве альтернативы, если сборка была загружена в первую очередь, для проверки информации о сборке, такой как publicKey, лучшим способом было бы не загружать ее, а проверять информацию, сначала загружая только AssemblyName :

AssemblyName an = AssemblyName.GetAssemblyName ("myfile.exe");
byte[] publicKey = an.GetPublicKey();
CultureInfo culture = an.CultureInfo;
Version version = an.Version;

EDIT

Если вам нужно отразить типы в сборке, не добавляя сборку в домен приложения, вы можете использовать метод Assembly.ReflectionOnlyLoadFrom. это позволит вам взглянуть на их типы в сборке, но не даст вам возможности их создать, а также не загрузит сборку в домен приложений.

Посмотрите на этот пример как объяснение

public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}
...