Вопрос по .net, c#, appdomain – Как выгрузить сборку из основного AppDomain?

41

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

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

var assembly = Assembly.LoadFrom( FilePathHere );

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

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

Старайтесь не использовать LoadFrom, он находится в другом контексте, чем контекст Load, и может вызвать проблемы. user7116
Хороший вопрос, но я не вижу CLEAR-ответа о том, как разрешить var assembly = Assembly.LoadFrom (FilePathHere); Academy of Programmer

Ваш Ответ

8   ответов
1

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

0

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

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

EDIT

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

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

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
}
4

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

15

Вот почему:

You are running that code in the app domain. That means there are potentially call sites and call stacks with addresses in them that are expecting to keep working.

Say you did manage to track all handles and references to already running code by an assembly. Assuming you didn't ngen the code, once you successfully freed up the assembly, you have only freed up the metadata and IL. The JIT'd code is still allocated in the app domain loader heap (JIT'd methods are allocated sequentially in a buffer in the order in which they are called).

The final issue relates to code which has been loaded shared, otherwise more formally know as "domain neutral" (check out /shared on the ngen tool). In this mode, the code for an assembly is generated to be executed from any app domain (nothing hard wired).

It is recommended that you design your application around the application domain boundary naturally, where unload is fully supported.

20

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

var assembly = Assembly.LoadFrom( FilePathHere );

использовать этот:

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

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

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

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

assembly = null;
По & quot;Cannot use AppDomain& Quot; Вы имеете в виду, что не можете инициировать один внутри этой сборки, или вы могли бы быть более конкретным? Как насчетAppDomain.CurrentDomain.Load(File.ReadAllBytes(FilePathHere)); Есть ли реальное отличие от Assembly.Load в этом конкретном сценарии?
Примерно 1 день боролся с маршалингом, новыми доменами приложений и прочим. Это прекрасно работает для меня!
1

но может помочь кому-то. Вы можете загрузить файл из потока и выпустить его. Это сработало для меня. Я нашел решениеВОТ.

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

33

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

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

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

Я думал, что это изменилось с .Net 3.5? Derik Whittaker
Нет планов разрешить выгрузку сборки из домена приложения (я не ожидаю, что и они тоже, это очень сложно сделать, и те, кто заботится, будут использовать более безопасный и чистый обходной путь). Лучшее, что вы можете сделать - это легкий код, о котором упоминал Хот
9

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

@jkff: К сожалению, если вы используете MarshalByRefObject, как в примере PingPong, Assembly.LoadFrom будет выполняться так же, как в основном AppDomain, поэтому выгрузка временного AppDomain все равно приведет к старой проблеме невозможности выгрузить сборку. Я думаю, что вам, возможно, придется каким-то образом сериализовать нужные данные из временного домена приложений без маршалинга, если вы хотите получить к нему доступ и все еще иметь возможность выгрузить сборку.
@jkff: Вы можете быть правы, хотя ... но это не так просто, как описано в примере MSDN. Вероятно, следует использовать tempAppDomain.CreateInstanceAndUnwrap ... и может понадобиться даже использовать AppDomain.GetData и SetData. (Это действительно не захламляет домен приложения, если его единственная цель - загружать и выгружать.)
См. AppDomain.DoCallback, а также MarshalByRefObject: вы создаете MarshalByRefObject & quot; invoker & quot; с помощью метода, который делает то, что вам нужно, и возвращает что-то в своих изменяемых полях, вы создаете временный домен AppDomain и вызываете dom.DoCallback (invoker.DoSomething), чтобы заставить этот объект делать то, что вы хотите; Затем вы собираете результаты из invoker в своем домене приложения и выгружаете временный домен.

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