2013-05-03 5 views
3

Мне нужно загрузить .dll (плагины) в другой домен. В основном приложении я ничего не знаю о типах плагинов, только что они реализуют общий интерфейс ICommonInterface с некоторыми методами. Поэтому этот код не помог, потому что я не могу создать экземпляр с типом интерфейса.Загрузка DLL в отдельный AppDomain с известным только общим интерфейсом

AppDomain domain = AppDomain.CreateDomain("New domain name"); 
//Do other things to the domain like set the security policy 

string pathToDll = @"C:\myDll.dll"; //Full path to dll you want to load 
Type t = typeof(TypeIWantToLoad); 
TypeIWantToLoad myObject = (TypeIWantToLoad)domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName); 

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

UPDATE: Вот мой код: MainLib.dll

namespace MainLib 
{ 
public interface ICommonInterface 
{ 
    void ShowDllName(); 
} 
} 

PluginWithOutException.dll

namespace PluginWithOutException 
{ 
public class WithOutException : MarshalByRefObject, ICommonInterface 
{ 
    public void ShowDllName() 
    { 
     Console.WriteLine("PluginWithOutException"); 
    } 
} 
} 

PluginWithException.dll

namespace PluginWithException 
{ 
public class WithException : MarshalByRefObject, ICommonInterface 
{ 
    public void ShowDllName() 
    { 
     Console.WriteLine("WithException"); 
     throw new NotImplementedException(); 
    } 
} 
} 

И основное применение:

 static void Main(string[] args) 
    { 
     string path = @"E:\Plugins\"; 
     string[] assemblies = Directory.GetFiles(path); 

     List<string> plugins = SearchPlugins(assemblies); 

     foreach (string item in plugins) 
     { 
      CreateDomainAndLoadAssebly(item); 
     } 

     Console.ReadKey(); 
    } 

    public static List<string> SearchPlugins(string[] names) 
    { 
     AppDomain domain = AppDomain.CreateDomain("tmpDomain"); 
     domain.Load(Assembly.LoadFrom(@"E:\Plugins\MainLib.dll").FullName); 
     List<string> plugins = new List<string>(); 

     foreach (string asm in names) 
     { 
      Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName); 

      var theClassTypes = from t in loadedAssembly.GetTypes() 
           where t.IsClass && 
             (t.GetInterface("ICommonInterface") != null) 
           select t; 
      if (theClassTypes.Count() > 0) 
      { 
       plugins.Add(asm); 
      } 
     } 
     AppDomain.Unload(domain); 
     return plugins; 
    } 

У плагинов и основного приложения есть ссылка на MainLib.dll. Основная цель - не загружать сборки в домене по умолчанию, а загружать их в другие домены, поэтому, когда они мне не нужны, я просто выгружаю() домен и выгружаю все плагины из приложения.

Пока исключение составляет FileNotFoundException, Could not load file or assembly 'PluginWithException, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.) на строку Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName); (я пытаюсь загрузить плагин с именем PluginWithException), Я удалить все зависимости в плагинах, кроме арматуры системы, я загрузил System.dll в этой области (она загружена правильно и он находится в домене), но все еще не могут загрузить плагины в домен. Также я проверил, что PluginWithException имеет 2 зависимости - mscorlib и MainLib, и все они загружены в этот домен.

ОБНОВЛЕНИЕ: Here Я задал этот вопрос более подробно.

ответ

1

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

How to Load an Assembly to AppDomain with all references recursively?

После загрузки сборки, вы можете использовать Assembly.GetTypes() и перебирать, чтобы найти типы, которые реализуют свой интерфейс.

+0

Хорошо, но это сборки будут загружены в домене по умолчанию и будет жить там, пока я не закрыть приложение. И я хочу загрузить сборку в другом домене и выгрузить ее со всеми сборками, когда мне это нужно. –

+1

И проблема в том, что я не могу использовать код 'Assembly a = anotherDomain.Load (Assembly.LoadFrom (path) .FullName);', он выдает исключение fileNotFountException, но DLL существует по этому пути –

+0

Справедливые точки.Это не так просто, как кажется. Я переработал свой ответ. – Dan

1

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

[Serializable, ClassInterface(ClassInterfaceType.AutoDual)] 
class helperDomain<T>: MarshalByRefObject where T: class 
{ 
    #region private 
    private AppDomain _app_domain; 
    private AppDomainSetup _app_domain_info; 

    private string _assembly_class_name; 
    private string _assembly_file; 
    private string _assembly_file_name; 
    private T _inner_class; 
    private bool _load_ok; 
    private string _loading_errors; 
    private string _path; 
    #endregion 

    #region .ctor 
    public helperDomain(string AssemblyFile, 
     string configFile = null, string domainName) 
    { 
     this._load_ok = false; 
     try 
     { 
      this._assembly_file = AssemblyFile; //full path to assembly 
      this._assembly_file_name = System.IO.Path.GetFileName(this._assembly_file); //assmbly file name 
      this._path = System.IO.Path.GetDirectoryName(this._assembly_file); //get root directory from assembly path 
      this._assembly_class_name = typeof(T).ToString(); //the class name to instantiate in the domain from the assembly 
      //start to configure domain 
      this._app_domain_info = new AppDomainSetup(); 
      this._app_domain_info.ApplicationBase = this._path; 
      this._app_domain_info.PrivateBinPath = this._path; 
      this._app_domain_info.PrivateBinPathProbe = this._path; 
      if (!string.IsNullOrEmpty(configFile)) 
      { 
       this._app_domain_info.ConfigurationFile = configFile; 
      } 
      //lets create the domain 
      this._app_domain = AppDomain.CreateDomain(domainName, null, this._app_domain_info); 
      //instantiate the class 
      this._inner_class = (T) this._app_domain.CreateInstanceFromAndUnwrap(this._assembly_file, this._assembly_class_name); 
      this._load_ok = true; 
     } 
     catch (Exception exception) 
     { 
      //There was a problema setting up the new appDomain 
      this._load_ok = false; 
      this._loading_errors = exception.ToString(); 
     } 
    } 
    #endregion 


    #region public properties 
    public string AssemblyFile 
    { 
     get 
     { 
      return _assembly_file; 
     } 
    } 

    public string AssemblyFileName 
    { 
     get 
     { 
      return _assembly_file_name; 
     } 
    } 

    public AppDomain AtomicAppDomain 
    { 
     get 
     { 
      return _app_domain; 
     } 
    } 

    public T InstancedObject 
    { 
     get 
     { 
      return _inner_class; 
     } 
    } 

    public string LoadingErrors 
    { 
     get 
     { 
      return _loading_errors; 
     } 
    } 

    public bool LoadOK 
    { 
     get 
     { 
      return _load_ok; 
     } 
    } 

    public string Path 
    { 
     get 
     { 
      return _path; 
     } 
    } 
    #endregion 
} 

, а затем загрузить плагины (каждый в другой папке).

foreach(string pluginassemblypath in pluginspaths) 
{ 
    //Each pluginassemblypath (as it says..) is the full path to the assembly 
    helperDomain<IPluginClass> isoDomain = 
     helperDomain<IPluginClass>(pluginassemblypath, 
      pluginassemblypath + ".config", 
      System.IO.Path.GetFileName(pluginassemblypath) + ".domain"); 
    if (isoDomain.LoadOK) 
    { 
     //We can access instance of the class (.InstancedObject) 
     Console.WriteLine("Plugin loaded..." + isoDomain.InstancedObject.GetType().Name); 
    } 
    else 
    { 
     //Something happened... 
     Console.WriteLine("There was en error loading plugin " + 
      pluginassemblypath + " - " + helperDomain.LoadingErrors); 
    } 
} 

Надеется, что это будет поможет вам ...

+0

Спасибо! Я нашел ответ в другой теме, но спасибо! –

+0

Вы g вызывая имя 'T',' this._assembly_class_name = typeof (T) .ToString(); 'затем создавая экземпляр' this._app_domain.CreateInstanceFromAndUnwrap (this._assembly_file, this._assembly_class_name); '. И T жестко закодирован в параметр типового типа. Поскольку пользователь сказал, что он не знает, что такое T, только то, что T реализует общий интерфейс. – Despertar

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