将 DLL 加载到单独的 AppDomain 中,只有已知的通用接口 [英] Loading DLLs into a separate AppDomain with known only common interface

查看:26
本文介绍了将 DLL 加载到单独的 AppDomain 中,只有已知的通用接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to load .dll(plugins) in another domain. In main app I don't know anything about plugins types, only that they implement common interface ICommonInterface with some methods. So this code wouldn't help, because I can't create an instance with interface type.

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

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

My question is how I can load assembly in new domain and get the instance, if I know only interface name which implements type I want to create.

更新:这是我的代码:主库.dll

UPDATE: Here is my code: MainLib.dll

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

PluginWithOutException.dll

PluginWithOutException.dll

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

PluginWithException.dll

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:PluginsMainLib.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.主要目的是不要在默认域中加载程序集,而是将它们加载到另一个域,所以当我不需要它们时,我只是 Unload() 域并从应用程序中卸载所有插件.

Plugins and main app have reference to MainLib.dll. The main aim is to not to load assemblies in default domain, but load them to another domains, so when I don't need them, I just Unload() domain and unload all plugins from application.

目前异常是 FileNotFoundException,无法加载文件或程序集PluginWithException,版本=1.0.0.0,Culture=neutral,PublicKeyToken=null"或其依赖项之一.系统找不到指定的文件.) on string Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName);(我试图加载名为 PluginWithException 的插件),我已经删除了插件中的所有依赖项,除了 System,我在这个域中加载了 System.dll(它加载正确并且它在域中),但仍然无法将插件加载到域中.我还检查了 PluginWithException 有 2 个依赖项 - mscorlib 和 MainLib,并且所有这些都加载到该域中.

For now the exception is 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.) on string Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName);(I trying to load plugin with name PluginWithException), I've delete all the dependencies in plugins, exept System, I loaded System.dll in this domain(it loaded correct and it is in domain), but still cant load plugins into domain. Also I checked, that PluginWithException has 2 dependencies - mscorlib and MainLib, and all of them loaded to this domain.

更新:这里我问了这个问题更多详情.

UPDATE: Here I asked this question with more details.

推荐答案

我不确定这是否是您需要的,我会尽力帮助您解决这个问题.这就是我加载插件程序集的方式.我使用一个帮助程序类来管理新的 AppDomain 和该程序集上的类的实例.这是助手类:

I'm not sure if it's what you need, i'd try to help you with this. This is how I do to load plugin assemblies. I use a helper class to manage new AppDomain and the instance of the class on that assembly. This is the helper class:

[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
}

然后加载插件(每个在不同的文件夹中).

and then load plugins (each in a diferent folder).

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

希望能帮到你...

这篇关于将 DLL 加载到单独的 AppDomain 中,只有已知的通用接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆