как удалить сборку плагина после AppDomain.Unload(domain)

у меня странная проблема. я хотел бы удалить сборку (plugin.dll на жестком диске), которая уже загружена, но сборка заблокирована операционной системой (vista), даже если я ее выгрузил.

f.e.

AppDomainSetup setup = new AppDomainSetup();
setup.ShadowCopyFiles = "true";
AppDomain appDomain = AppDomain.CreateDomain(assemblyName + "_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
IPlugin plugin = (IPlugin)appDomain.CreateInstanceFromAndUnwrap(assemblyName,                        "Plugin.MyPlugins");

Мне также нужна информация о сборке, потому что я не знаю, какие классы в сборке плагинов реализуют интерфейс IPlugin. Должна быть возможность иметь более одного плагина в одной сборке плагинов.

Assembly assembly = appDomain.Load(assemblyName);
if (assembly != null) {
   Type[] assemblyTypes = assembly.GetTypes();
   foreach (Type assemblyTyp in assemblyTypes) {
      if (typeof(IPlugin).IsAssignableFrom(assemblyTyp)) {
         IPlugin plugin = (IPlugin)Activator.CreateInstance(assemblyTyp);
         plugin.AssemblyName = assemblyNameWithEx;
         plugin.Host = this;
      }
   }
}
AppDomain.Unload(appDomain);

Как можно получить информацию о сборке из домена приложения, не блокируя сборку?

с уважением


person Ase    schedule 08.01.2009    source источник


Ответы (5)


Я думаю, что у меня есть ответ! ответ от Øyvind Skaar не сработает, если вы хотите удалить загруженную сборку.

вместо

using (FileStream dll = File.OpenRead(path))
{
   fileContent = new byte[dll.Length];
   dll.Read(fileContent, 0, (int)dll.Length);
}
Assembly assembly = appDomain.Load(fileContent);

вы должны использовать

byte[] b = File.ReadAllBytes(assemblyName);
assembly = Assembly.Load(b);

с уважением

person Tch    schedule 12.01.2009
comment
Когда я пробовал, все работало нормально, но у вас все равно короче ;) - person Øyvind Skaar; 12.01.2009
comment
Есть много подобных вопросов о выгрузке DLL и использовании отдельных AppDomains, но они, кажется, не работают, когда вы действительно хотите удалить DLL. Это определенно помогает, несмотря ни на что :) - person Jedidja; 25.07.2013
comment
Хороший! Даже не нужен еще один домен приложения. - person Thomas Eyde; 18.08.2015
comment
это не работает, если вы используете другой домен приложения, но это определенно лучший подход, чем усложнение с использованием домена приложения :) - person am05mhz; 13.01.2016
comment
Мне непонятно, как выгружается .dll, если выгружать можно только AppDomains. Решение, использующее массив байтов, похоже, не использует AppDomain. Может кто-нибудь уточнить? - person ; 13.11.2016
comment
Меня интересует файл .config. - person Yola; 26.03.2021

Я знаю, что эта ветка довольно мертва, но сейчас я работаю над этим и только что получил ответ (в 1:30 утра...)

AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
AppDomain app = AppDomain.CreateDomain("YaCsi", null, setup);
app.DoCallBack(LoaderCallback);
AppDomain.Unload(app);
File.Delete("__YaCsi_Test01.dll");

static void LoaderCallback()
{
    byte[] raw = File.ReadAllBytes("__YaCsi_Test01.dll");
    Assembly yacsi = Assembly.Load(raw);
    ((IScript)yacsi.CreateInstance("Script")).Go();
}

И это на самом деле не выдает никаких исключений!!! Надеюсь, что кто-то прочитает это и ответит на этот вопрос!

person Community    schedule 19.03.2010
comment
Это правильно. Это должно работать. Причина, по которой другой способ не работает, заключается в следующем: при вызове app.Load() сборка загружается в домен приложения app, а также в домен приложения, в котором выполняется код. После выгрузки app сборка по-прежнему загружается в другом домене приложения. Использование app.DoCallBack приводит к тому, что код запускается в app и, таким образом, сборка загружается только в app. (источники: msdn.microsoft.com/en-us/library/36az8x58.aspx и msdn.microsoft.com/en-us /библиотека/) - person Matthijs Wessels; 14.12.2011

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

byte[] fileContent;
string path = "../../../test/bin/Debug/test.dll"; //Path to plugin assembly
using (FileStream dll = File.OpenRead(path))
{
   fileContent = new byte[dll.Length];
   dll.Read(fileContent, 0, (int)dll.Length);
}
Assembly assembly = appDomain.Load(fileContent);
File.Delete(path);
person Øyvind Skaar    schedule 11.01.2009
comment
это должно, но это не так. :( UnauthorizedAccessException в File.Delete(путь); - person Ase; 12.01.2009
comment
Можете ли вы удалить файл, если сначала не загрузите сборку? - person Øyvind Skaar; 12.01.2009

Смотрите эти страницы:

Установите новый AppDomain AppDomainSetup с помощью LoaderOptimization.MultiDomainHost

E.g.

domainnew = AppDomain.CreateDomain(newdomain_name, null, new AppDomainSetup {
        ApplicationName = newdomain_name,
        ApplicationBase = assembly_directory,
        ConfigurationFile = ConfigurationManager.OpenExeConfiguration(assemblylocation).FilePath,
        LoaderOptimization = LoaderOptimization.MultiDomainHost,
        ShadowCopyFiles = shadowcopy ? "true" : "false",
    }
);
person kiii    schedule 29.02.2012

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

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

Я не думаю, что это прямо отвечает на ваш вопрос, но, вероятно, решает вашу проблему.

person Stever B    schedule 08.01.2009