2013-05-03 31 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); 

我的问题是如何能在新的领域加载程序集,并得到例如,如果我知道它实现了I型只希望创建接口名称。

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插件),我已经删除插件的所有依赖,exept系统,我在这个领域加载System.dll中(它加载正确的,它在域中),但仍然不能将插件加载到域中。此外,我检查,PluginWithException有2个依赖项 - mscorlib和MainLib,并将它们全部加载到此域。

更新:Here我问了这个问题的更多细节。

回答

1

这个问题似乎与你想要做的事情有关。

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

加载了组装后,您可以使用Assembly.GetTypes()和重复,以找到实现你的接口类型。

+0

好吧,不过这集将在默认域加载,将生活在那里,直到我关闭应用程序。我想在另一个域中加载程序集,并在需要时使用所有程序集卸载它。 – 2013-05-03 15:52:44

+1

问题在于我无法使用代码'Assembly a = anotherDomain.Load(Assembly.LoadFrom(path).FullName);',它抛出fileNotFountException,但是.dll存在于此路径 – 2013-05-03 15:55:38

+0

Fair point。这并不像看起来那么直截了当。我重新回答了我的答案。 – Dan 2013-05-03 16:11:21

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

谢谢!我找到了另一个主题的答案,但谢谢! – 2013-06-11 21:14:47

+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 2014-05-29 21:13:20

相关问题