• .net 动态加载Dll


    在程序正在使用的过程中,常常需要升级DLL。这时,如果dll已经被主程序引用,则无法修改,这样的需求应该很常见。换个角度,可以理解成程序的升级或者修改Bug的功能。

    以下通过动态的加载Dll来解决这个问题。

    整个思路的前提是,动态调用的东西和前台需要的功能通过代理IBaseInterface连接起来,也就是说动态dll里面的类和Proxy都需要实现这个接口。

    namespace BaseInterface
    {
        public interface IBaseInterface
        {
            string GetString();
        }
    }

    核心代码:Proxy.dll

    namespace Proxy
    {
        internal class AppDomainCore
        {
            public AppDomain DefaultAppDomain { get; private set; }
            public string DefaultAppDomainName { get; private set; }
    
            public AppDomainCore(string appDomainName)
            {
                DefaultAppDomainName = appDomainName;
                AppDomainSetup setup = new AppDomainSetup();
                setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
                setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    
                Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
                DefaultAppDomain = AppDomain.CreateDomain(appDomainName, evidence, setup);
            }
    
            public bool ClearAppDomain()
            {
                try
                {
                    AppDomain.Unload(DefaultAppDomain);
                    DefaultAppDomain = null;
                    return true;
                }
                catch { return false; }
            }
    
            ~AppDomainCore()
            {
                ClearAppDomain();
            }
        }
    }
    namespace Proxy
    {
        internal class AssemblyCore
        {
            public string ActivedAssemblyName { get; private set; }
            public string CurrentType { get; private set; }
            public FileInfo DefaultAssemblyFile { get; private set; }
    
            public AssemblyCore(string assemblyName, string type)
            {
                ActivedAssemblyName = assemblyName;
                CurrentType = type;
    
                try
                {
                    DefaultAssemblyFile = new FileInfo(assemblyName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
    }
    namespace Proxy
    {
        public class Proxy : BaseInterface.IBaseInterface
        {
            AssemblyCore _assemblyCore;
            AppDomainCore _appDomainCore;
    
            public string DefaultAssemblyName { get { return _assemblyCore.ActivedAssemblyName; } }
            public string DefaultAppDomainName { get { return _appDomainCore.DefaultAppDomainName; } }
    
            public Proxy(string assemblyName, string typeName, string appDomainName)
            {
                _assemblyCore = new AssemblyCore(assemblyName, typeName);
                _appDomainCore = new AppDomainCore(appDomainName);
            }
    
            public void UnLoad()
            {
                _appDomainCore.ClearAppDomain();
            }
    
            BaseInterface.IBaseInterface _proxy;
            public string GetString()
            {
                if (_proxy == null)
                    _proxy = _appDomainCore.DefaultAppDomain.CreateInstanceFromAndUnwrap(
                        _assemblyCore.ActivedAssemblyName, _assemblyCore.CurrentType) 
                        as BaseInterface.IBaseInterface;
                return _proxy.GetString();
            }
        }
    }

    以上代码在项目Proxy里面写入,是动态加载Dll的核心代码。

    在Proxy里面,其中AppDomainCore根据传递的参数生成新的AppDomain, AssemblyCore则根据传递的参数生成新的FileInfo. 在Proxy类里面,同时定义一个AssemblyCore和AppDomainCore,根据方法:_appDomainCore.DefaultAppDomain.CreateInstanceFromAndUnwrap(_assemblyCore.ActivedAssemblyName, _assemblyCore.CurrentType), 动态的生成实例,最后用as 转换成接口IBaseInterface,通过调用接口的GetString方法来调用dll里面的方法。

    一下为模拟的两个Dll类,

    namespace Assembly1
    {
        [Serializable]
        public class ClassLibrary : MarshalByRefObject, BaseInterface.IBaseInterface
        {
            public string GetString()
            {
                return "Assembly1.ClassLibrary";
            }
        }
    }
    namespace Assembly2
    {
        [Serializable]
        public class ClassLibrary : MarshalByRefObject, BaseInterface.IBaseInterface
        {
            public string GetString()
            {
                return "Assembly2.ClassLibrary";
            }
        }
    }

    分别生成到Assembly v1.0.dll和Assembly v2.0.dll中。

    最终的界面代码:

    namespace DynamicDll
    {
        public partial class Form1 : Form
        {
            Proxy.Proxy _proxy;
            public Form1()
            {
                InitializeComponent();
                LoadDll("Assembly v1.0.dll", "Assembly1.ClassLibrary", "Domain1");
                radV1.Click += (a, b) => LoadDll("Assembly v1.0.dll", "Assembly1.ClassLibrary", "Domain1");
                radV2.Click += (a, b) => LoadDll("Assembly v2.0.dll", "Assembly2.ClassLibrary", "Domain2");
            }
    
            void LoadDll(string assName, string type, string appName)
            {
                if (_proxy != null) _proxy.UnLoad();
                _proxy = new Proxy.Proxy(assName, type, appName);
                lblCurrentAppDomain.Text = _proxy.DefaultAppDomainName;
                lblCurrentAssembly.Text = _proxy.DefaultAssemblyName;
                lblMainAppDomain.Text = AppDomain.CurrentDomain.FriendlyName;
            }
    
            private void btnRes_Click(object sender, EventArgs e)
            {
                txtRes.Text = _proxy.GetString();
            }
        }
    }

     

    查看项目Dynamic的依赖项,可以很清楚的看到:它只依赖BaseInterface和Proxy两个项目,与Assembly v1.0和v2.0都无关。

    也就是说,程序运行的时候,可以修改Assembly v1.0和v2.0里面的代码,重新生成,同时替换运行目录下的dll。

  • 相关阅读:
    Git+GitHub+SaltStack
    系统运维
    Linux之Ubuntu
    TCP/IP 必知必会的十个问题
    Github常见操作和常见错误!
    Git钩子:自定义你的工作流
    Spring 梳理
    Spring 梳理
    Spring 梳理
    Spring boot 官网学习笔记
  • 原文地址:https://www.cnblogs.com/icyJ/p/dynamic_Dll.html
Copyright © 2020-2023  润新知