将DLL加载到具有已知唯一公共接口的单独AppDomain中

我需要在另一个域中加载.dll(插件)。 在主应用程序中,我对插件类型一无所知,只是他们用一些方法实现了通用接口ICommonInterface。 因此,这段代码无济于事,因为我无法创建具有接口类型的实例。

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); 

我的问题是我如何在新域中加载程序集并获取实例,如果我只知道实现我想要创建的类型的接口名称。

更新:这是我的代码: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 plugins = SearchPlugins(assemblies); foreach (string item in plugins) { CreateDomainAndLoadAssebly(item); } Console.ReadKey(); } public static List SearchPlugins(string[] names) { AppDomain domain = AppDomain.CreateDomain("tmpDomain"); domain.Load(Assembly.LoadFrom(@"E:\Plugins\MainLib.dll").FullName); List plugins = new List(); 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。 主要目的是不在默认域中加载程序集,而是将它们加载到另一个域,因此当我不需要它们时,我只需卸载()域并从应用程序卸载所有插件。

目前,exception是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.) 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,并且所有这些依赖项都加载到了这个域。

更新:我在这里向更多细节问了这个问题。

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

如何以递归方式将所有引用加载到AppDomain的程序集?

加载程序集后,可以使用Assembly.GetTypes()并迭代以查找实现接口的类型。

我不确定这是不是你需要的,我会尽力帮助你。 这是我如何加载插件程序集。 我使用一个帮助器类来管理新的AppDomain和该程序集上的类的实例。 这是助手类:

 [Serializable, ClassInterface(ClassInterfaceType.AutoDual)] class helperDomain: 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 isoDomain = helperDomain(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); } } 

希望它会帮助你……