Загрузка / выгрузка сборки в другой домен приложений - PullRequest
22 голосов
/ 25 января 2010

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

Сборки, которые будут загружаться, являются плагинами в моей структуре плагинов. У них вообще нет точки входа. Я знаю только то, что они содержат некоторые типы, которые реализуют данный интерфейс. Старый не-AppDomain-код выглядит следующим образом (слегка укороченный):

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Assembly asm = Assembly.LoadFrom(path);
    Type[] types = asm.GetExportedTypes();
    foreach (Type t in types)
    {
        if ((t.GetInterface("IStarter") != null) && !t.IsAbstract)
        {
            object tempObj = Activator.CreateInstance(t);
            MethodInfo info = t.GetMethod("GetParameters");
            if (info != null)
            {
                return info.Invoke(tempObj, null) as string;
            }
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("MyProject.View,"))
    {
        string path = Path.GetFullPath("C:\view.dll"));
        return Assembly.LoadFrom(path);
    }
    return null;
}

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

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain domain = AppDomain.CreateDomain("TempDomain");
    domain.AssemblyResolve += CurrentDomain_AssemblyResolve;  // 1. Exception here!!
    domain.ExecuteAssembly(path);  // 2. Exception here!!
    domain.CreateInstanceFrom(...);  // 3. I have NO clue, how the type is named.
    domain.Load(...);  // 4. I have NO clue, how the assembly is named.
    domain.DoCallBack(...); // 5. Exception here!!
    // ...
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Как видите, я поставил 5 случаев.

  1. Если я задаю обработчик событий, я получаю исключение, что сборка (это SnapIn. Консоли управления (mmc.exe) не может быть найдена / загружена.

  2. ExecuteAssembly не находит точку входа (ну, ее нет).

  3. Понятия не имею, как называется тип. Как загрузить по интерфейсу?

  4. Аналогично 3. Как получить название сборки?

  5. Та же ошибка, что и в 1.

Я думаю, что проблема в том, что консоль управления каким-то образом или я просто не понимаю, что я делаю неправильно. Любая помощь приветствуется.

ОБНОВЛЕНИЕ 1

Я попытался использовать опубликованное прокси-решение.

AppDomain domain = AppDomain.CreateDomain("TempDomain");
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
    typeof(InstanceProxy)).FullName, typeof(InstanceProxy).ToString()) as InstanceProxy;
if (proxy != null)
{
    proxy.LoadAssembly(path);
}
AppDomain.Unload(domain);

public class InstanceProxy : MarshalByRefObject
{
    public void LoadAssembly(string path)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        Assembly asm = Assembly.LoadFrom(path);
        Type[] types = asm.GetExportedTypes();
        // ...see above...
    }
}

Это тоже не работает. При попытке создать объект прокси я получаю исключение:

Не удалось загрузить файл или сборку 'MyProject.SnapIn, Version = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null' или одну из ее зависимостей. Система не может найти указанный файл.

Файл в сообщении об ошибке загружен в mmc (SnapIn). Есть идеи, как исправить эту ошибку? AppDomain.AssemblyResolve не вызывается (ни в старом, ни в новом домене).

ОБНОВЛЕНИЕ 2

Я сейчас попробовал решение с помощью AppDomainSetup. Теперь исключение изменилось на:

Не удалось загрузить файл или сборку 'file: /// C: /Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL' или одну из ее зависимостей. Указанное имя сборки или кодовая база недопустимы. (Исключение из HRESULT: 0x80131047)

Есть идеи?

Ответы [ 3 ]

13 голосов
/ 25 января 2010

Попробуйте это:

namespace SeperateAppDomainTest
{
    class Program
    {
        static void Main(string[] args)
        {
            LoadAssembly();
        }

        public static void LoadAssembly()
        {
            string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
            AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
            var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
            ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
            Console.WriteLine(c == null);

            Console.ReadKey(true);
        }
    }

    public class ProxyClass : MarshalByRefObject { }
1 голос
/ 25 января 2010

Взгляните на этот предыдущий ответ: Как загрузить сборку в другой домен приложений в Windows Mobile (.NET CF)? . Этот ответ создает прокси-класс, который запускается в новом контексте AppDomain, поэтому вы можете полностью контролировать инициализацию.

Вы можете создать Start() метод в ServiceApplicationProxy классе и просто вызывать его как обычно с вашего хостера с proxy.Start().

0 голосов
/ 24 ноября 2016

https://msdn.microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx

указывает, что

TYPENAME Тип: System.String

The fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName

свойство.

Поэтому попробуйте позвонить с полным именем, вместо использования typeof(InstanceProxy).ToString() используйте строку / текст "<<Namespace>>.InstanceProxy"

как показано ниже

InstanceProxy proxy = domain.CreateInstanceAndUnwrap(path, "<<Namespace>>.InstanceProxy") as InstanceProxy;
...