2010-01-25 8 views
21

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

Сборка, собирающаяся загрузить, - это плагины в моем плагине. У них нет точки входа. Все, что я знаю, это то, что они содержат некоторые типы, которые реализуют данный интерфейс. Старый, не 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; 
} 

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

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. Если установить обработчик событий, я получаю исключение, что сборка (это консоль управления (mmc.exe) SnapIn. Не может быть найден/загружен.

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

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

  4. Подобно 3. Как получить имя сборки?

  5. Та же самая ошибка в 1.

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

UPDATE 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 = neutral, PublicKeyToken = null» или одну из его зависимостей. Система не может найти указанный файл.

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

UPDATE 2

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

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

Любая идея?

+1

Вы пытались создать класс, который наследуется от MarshallByRef действовать в качестве прокси-сервера и пусть он делает эту грязную работу в контексте нового приложения? –

+0

Будет ли этот класс находиться в сборке для загрузки или в уже загруженной сборке (тот, кто пытается загрузить остальные)? – Scoregraphic

+0

, пожалуйста, см. Мой ответ ниже –

ответ

11

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

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 { } 
+0

Спасибо за подсказку с AppDomainSetup, но это не решает проблему. См. Мой обновленный вопрос – Scoregraphic

1

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

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

+0

Спасибо за ваш ответ. Я пробовал это, но я все еще получаю ошибки. См. Мое обновление в исходном вопросе. – Scoregraphic

0

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; 
+0

Не будет ли 'typeof (InstanceProxy) .FullName' лучше, чем hardcoding пространство имен + typename? – Maarten

 Смежные вопросы

  • Нет связанных вопросов^_^