动用程序域达成程序集动态卸载或加载,NET插件才能

  AppDomain 表示应用程序域,它是三个应用程序在其间举办的单独环境。种种应用程序只有三个主应用程序域,不过三个应用程序能够成立多个子应用程序域。

C# 通过 AppDomain 应用程序域得以达成程序集动态卸载或加载,

  AppDomain 表示应用程序域,它是四个应用程序在里面实行的单独环境。每种应用程序惟有三个主应用程序域,不过二个应用程序能够创制七个子应用程序域。

  因而能够通过 AppDomain
创造新的运用程序域,在新创立的子应用程序域中加载施行程序集并且在实行达成后刑释程序集能源,来达成系统在运营情况下,程序集的动态加载或卸载,从而到达系统运营中先后集热更新的目的。

以下为1体原理的实现代码

主应用程序入口:

using Kernel.ServiceAgent;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.App
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("");

            using (ServiceManager<IObjcet> manager = new ServiceManager<IObjcet>()) 
            {
                string result = manager.Proxy.Put("apprun one");
                Console.WriteLine(result);
                Console.WriteLine("");
                Console.WriteLine("                         Thread AppDomain info                             ");
                Console.WriteLine(manager.CotrProxy.FriendlyName);
                Console.WriteLine(Thread.GetDomain().FriendlyName);
                Console.WriteLine(manager.CotrProxy.BaseDirectory);
                Console.WriteLine(manager.CotrProxy.ShadowCopyFiles);
                Console.WriteLine("");
            }

            Console.ReadLine();
        }
    }
}

创设新的应用程序域并且在新的应用程序域中调用透西汉理类:

using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class ServiceManager<T> : IDisposable where T : class
    {
        private AppDomain ctorProxy = null;

        /// <summary>
        /// 应用程序运行域容器
        /// </summary>
        public AppDomain CotrProxy
        {
            get { return ctorProxy; }
        }

        private T proxy = default(T);

        public T Proxy
        {
            get
            {
                if (proxy == null)
                {
                    proxy = (T)InitProxy(AssemblyPlugs);
                }
                return proxy;
            }
        }

        private string assemblyPlugs;

        /// <summary>
        /// 外挂插件程序集目录路径
        /// </summary>
        public string AssemblyPlugs
        {
            get {
                assemblyPlugs = ConfigHelper.GetVaule("PrivatePath");
                if (assemblyPlugs.Equals("")){
                    assemblyPlugs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
                }
                if (!Directory.Exists(assemblyPlugs)) 
                {
                    Directory.CreateDirectory(assemblyPlugs);
                }
                return assemblyPlugs;
            }
            set { assemblyPlugs = value; }
        }

        public ServiceManager()
        {
            if (proxy == null)
            {
                proxy = (T)InitProxy(AssemblyPlugs);
            }
        }

        private T InitProxy(string assemblyPlugs)
        {
            try
            {
                //AppDomain.CurrentDomain.SetShadowCopyFiles();
                //Get and display the friendly name of the default AppDomain.
                //string callingDomainName = Thread.GetDomain().FriendlyName;

                //Get and display the full name of the EXE assembly.
                //string exeAssembly = Assembly.GetEntryAssembly().FullName;
                //Console.WriteLine(exeAssembly);

                AppDomainSetup ads = new AppDomainSetup();
                ads.ApplicationName = "Shadow";

                //应用程序根目录
                ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

                //子目录(相对形式)在AppDomainSetup中加入外部程序集的所在目录,多个目录用分号间隔
                ads.PrivateBinPath = assemblyPlugs;
                //设置缓存目录
                ads.CachePath = ads.ApplicationBase;
                //获取或设置指示影像复制是打开还是关闭
                ads.ShadowCopyFiles = "true";
                //获取或设置目录的名称,这些目录包含要影像复制的程序集
                ads.ShadowCopyDirectories = ads.ApplicationBase;

                ads.DisallowBindingRedirects = false;
                ads.DisallowCodeDownload = true;

                ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

                //Create evidence for the new application domain from evidence of
                Evidence adevidence = AppDomain.CurrentDomain.Evidence;

                // Create the second AppDomain.
                ctorProxy = AppDomain.CreateDomain("AD #2", adevidence, ads);

                //Type.GetType("Kernel.TypeLibrary.MarshalByRefType").Assembly.FullName
                string assemblyName = Assembly.GetExecutingAssembly().GetName().FullName;
                //string assemblyName = typeof(MarshalByRefType).Assembly.FullName

                // Create an instance of MarshalByRefObject in the second AppDomain. 
                // A proxy to the object is returned.

                Console.WriteLine("CtorProxy:" + Thread.GetDomain().FriendlyName);

                //TransparentFactory factory = (IObjcet)ctorProxy.CreateInstance("Kernel.TypeLibrary",
               "Kernel.TypeLibrary.TransparentFactory").Unwrap();
                TransparentAgent factory = (TransparentAgent)ctorProxy.CreateInstanceAndUnwrap(assemblyName, 
                              typeof(TransparentAgent).FullName);

                Type meetType = typeof(T);
                string typeName = AssemblyHelper.CategoryInfo(meetType);

                object[] args = new object[0];
                string assemblyPath = ctorProxy.SetupInformation.PrivateBinPath;

                //IObjcet ilive = factory.Create(@"E:\Plug\Kernel.SimpleLibrary.dll", "Kernel.SimpleLibrary.PlugPut", args);
                T obj = factory.Create<T>(assemblyPath, typeName, args);

                return obj;
            }
            catch (System.Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 卸载应用程序域
        /// </summary>
        public void Unload()
        {
            try
            {
                if (ctorProxy != null)
                {
                    AppDomain.Unload(ctorProxy);
                    ctorProxy = null;
                }
            }
            catch(Exception)
            {
                throw;
            }
        }

        public void Dispose()
        {
            this.Unload();
        }
    }
}

动用程序域达成程序集动态卸载或加载,NET插件才能。创造应用程序代理类:

using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class TransparentAgent : MarshalByRefObject
    {
        private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

        public TransparentAgent() { }

        /// <summary> Factory method to create an instance of the type whose name is specified,
        /// using the named assembly file and the constructor that best matches the specified parameters. </summary>
        /// <param name="assemblyFile"> The name of a file that contains an assembly where the type named typeName is sought. </param>
        /// <param name="typeName"> The name of the preferred type. </param>
        /// <param name="constructArgs"> An array of arguments that match in number, order,
     /// and type the parameters of the constructor to invoke, or null for default constructor. </param>
        /// <returns> The return value is the created object represented as IObjcet. </returns>
        public IObjcet Create(string assemblyFile, string typeName, object[] args)
        {
            return (IObjcet)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }

        public T Create<T>(string assemblyPath, string typeName, object[] args)
        {
            string assemblyFile = AssemblyHelper.LoadAssemblyFile(assemblyPath, typeName);
            return (T)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }
    }
}

享有涉嫌到须要动态加载或自由的财富,都供给放在代理类中举行操作,唯有在此代理类中开展托管的代码才是属于新建的利用程序域的操作。

using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class AssemblyHelper
    {
        /// <summary>
        /// 获取泛型类中指定属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static string CategoryInfo(Type meetType)
        {
            object[] attrList = meetType.GetCustomAttributes(typeof(CategoryInfoAttribute), false);
            if (attrList != null)
            {
                CategoryInfoAttribute categoryInfo = (CategoryInfoAttribute)attrList[0];
                return categoryInfo.Category;
            }
            return "";
        }

        public static string LoadAssemblyFile(string assemblyPlugs, string typeName)
        {
            string path = string.Empty;
            DirectoryInfo d = new DirectoryInfo(assemblyPlugs);
            foreach (FileInfo file in d.GetFiles("*.dll"))
            {
                Assembly assembly = Assembly.LoadFile(file.FullName);
                Type type = assembly.GetType(typeName, false);
                if (type != null)
                {
                    path = file.FullName;
                }
            }
            return path;
        }
    }
}

读取配置文件消息:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace Kernel.ServiceAgent
{
    public class ConfigHelper
    {
        public static string GetVaule(string configName)
        {
            string configVaule = ConfigurationManager.AppSettings[configName];
            if (configVaule != null && configVaule != "")
            {
                return configVaule.ToString();
            }
            return "";
        }
    }
}

计划文件有关铺排新闻:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <appSettings>
      <add key="PrivatePath" value="E:\Plugins"/>
    </appSettings>
</configuration>

成立接口新闻:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    [CategoryInfo("Kernel.SimpleLibrary.PlugPut", "")]
    public interface IObjcet
    {
        void Put();

        string Put(string plus);
    }
}

始建接口自定义属性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    /// <summary>
    /// 设置接口实现类自定义标注属性
    /// </summary>
    /// 
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
    public class CategoryInfoAttribute : Attribute
    {
        public string Category { get; set; }

        public string Describtion { get; set; }

        /// <summary>
        /// 设置实现类自定义标注属性
        /// </summary>
        /// <param name="category"></param>
        /// <param name="describtion"></param>
        public CategoryInfoAttribute(string category, string describtion)
        {
            this.Category = category;
            this.Describtion = describtion;
        }
    }
}

开创承袭至IObjcet接口带有具体操作的兑现类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kernel.Interface;

namespace Kernel.SimpleLibrary
{
    [Serializable]
    public class PlugPut : MarshalByRefObject, IObjcet
    {

        private string plugName = "my plugName value is default!";

        public string PlugName
        {
            get { return plugName; }
            set { plugName = value; }
        }

        public PlugPut() { }


        public PlugPut(string plusName) 
        {
            this.PlugName = plusName;
        }

        public void Put()
        {
            Console.WriteLine("Default plug value is:" + plugName);
        }

        public string Put(string plus)
        {
            Console.WriteLine("Put plus value is:" + plus);
            return ("-------------------- PlugPut result info is welcome -------------------------");
        }
    }
}

  承接至IObjcet接口带有具体操作的兑现类,就是属于需求动态替换更新的程序集,所以最佳将其编写翻译在多少个单独的次第集中,插件目录在陈设文件中可安顿,示例中放置在E:\Plugins
目录下,示例中代码最终将生成 Kernel.SimpleLibrary.DLL ,最终将编写翻译好的次第集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运维后将加载此程序集,加载落成运转实现后并释放此程序集。

  以下两句较为首要,最好设置一下,不设置的结果暂时髦未品味

  //获取或安装提示印象复制是开荒依然关闭
  ads.ShadowCopyFiles = “true”;
  //获取或安装目录的称呼,那么些目录包蕴要映像复制的主次集
  ads.ShadowCopyDirectories = ads.ApplicationBase;

  当程序运维起来后,程序集加载之后会在安装的行使程序域缓存目录中复制一份程序集的副本,然后运维别本中的程序集,释放掉自个儿加载的次序集。以上示例中会在主程序目录下生成二个Shadow
目录,此目录下富含了先后集的别本文件。

小节:

  假设在另3个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中使用CreateInstance中的Type重载创立对象,结果会是Type所属的顺序集会被投入到当前AppDomain中,然后Type的实例会在当前AppDomain中成立。

  只有后续至 马尔斯halByRefObject
的透北魏理类技能够进行跨域操作。**

  所以必要在继续至 马尔斯halByRefObject
的晶莹代理类中打开连锁操作然后回来给主应用程序域,唯有在代理类中实行的代码操作才是属于新建的行使程序域。不然别的运营代理类以外的代码都以属于主应用程序域。

  此章节只是疏解了先后集动态加载或卸载热插拔的完结格局,有关AppDomain
和 AppDomainSetup 具体音信方可参考MSDN上边包车型客车文书档案。

通过 AppDomain
应用程序域达成程序集动态卸载或加载,
AppDomain表示应用程序域,它是贰个应用程序在中间实行的独自环境。每一种应用程序…

  AppDomain 表示应用程序域,它是二个应用程序在内部实践的独门环境。各类应用程序只有贰个主应用程序域,可是贰个应用程序能够创设八个子应用程序域。

今日说一说.NET 中的插件才干,即
应用程序热晋级。在广大情状下、我们愿意用户对应用程序的升迁是无感知的,并且尽量不打断用户操作的。

  由此得以经过 AppDomain
创立新的运用程序域,在新创设的子应用程序域中加载施行程序集并且在进行落成后放走程序集能源,来实现系统在运作状态下,程序集的动态加载或卸载,从而实现系统运维中先后集热更新的目的。

  因而得以因而 AppDomain
成立新的接纳程序域,在新创立的子应用程序域中加载推行程序集并且在推行达成后获释程序集能源,来实现系统在运维景况下,程序集的动态加载或卸载,从而实现系统运营中先后集热更新的目标。

纵然在Web 只怕WebAPI上,由于多点的存在能够每个停用单点实行系统晋级,而不影响总体服务。但是客户端却不能够如此做,毕竟用户一向在接纳着。

  所谓应用程序域,.Net引进的三个定义,指的是1种境界,它标志了代码的运作范围,在在那之中产生的别的表现,包罗丰硕都不会潜移默化到任何应用程序域,起到安全隔开的效益。也能够看做是1个轻量级的进程。

  所谓应用程序域,.Net引进的2个概念,指的是一种境界,它标志了代码的运行范围,在里头发生的别样表现,包含足够都不会潜移默化到其余使用程序域,起到安全隔开分离的成效。也足以视作是二个轻量级的进度。

那即是说有未有一种格局,可以在用户无感知的事态下(即、不鸣金收兵进程的景况下)对客户端实行进步吗?

2个进度可以包涵多个应用程序域,各种域之间交互独立。如下是1个.net历程的三结合(图片源于互连网)

3个经过能够包蕴多个使用程序域,各类域之间相互独立。如下是一个.net进程的结缘(图片来源互联网)

答案是任其自流的,
那正是本人前天想说的插件才干、能够对应用程序进行热晋级。当然那种艺术也同样适用于
ASP.NET ,

美高梅开户网址 1

美高梅开户网址 2

而是当下小说是以 WPF为例子的,并且原理是1致的、代码逻辑也是同等的。

以下为一切原理的兑今世码

以下为整个原理的落到实处代码

一、应用程序域AppDomain

在介绍插件技能此前、大家须要先领会一些基础性的学问,第三个便是使用程序域AppDomain.

操作系统和周转时环境一般会在应用程序间提供某种格局的割裂。例如,Windows
使用进程来隔开分离应用程序。为保险在1个应用程序中运作的代码不会对别的不相干的应用程序发生不良影响,那种隔断是至关重要的。那种隔开分离可以为使用程序域提供安全性、可靠性,
并且为卸载程序集提供了恐怕。


.NET中使用程序域AppDomain是CL昂Cora的运维单元,它能够加载应用程序集Assembly、创造对象以及施行顺序。

在 CLQashqai里、AppDomain就是用来贯彻代码隔绝的,每3个AppDomain能够独立成立、运营、卸载。

有关AppDomain中的未处理非常:

若果暗中同意AppDomain监听了UnhandledException
事件,任何线程的别的未处理非常都会抓住该事件,无论线程是从哪个AppDomain中开端的。

假使一个线程起首于一个曾经济监察听了UnhandledException事件的 app domain,
那么该事件将要这几个app domain 中引发。

如果那些app domian 不是暗中认可的app domain, 并且 暗中认可 app domain
中也监听了UnhandledException 事件, 那么 该事件将会在七个app domain
中抓住。

美高梅开户网址 ,CLHaval启用时,会创造二个私下认可的AppDomain,程序的入口点正是在那个暗许的AppDomain中试行。

AppDomain是能够在运营时举办动态的创制和卸载的,正因如此,才为插件才能提供了根基(注:应用程序集和系列是不能卸载的,只能卸载整个AppDomain)。

AppDomain和其余概念之间的涉嫌

1、AppDomain vs 进程Process

AppDomain被创立在Process中,3个Process内能够有多少个AppDomain。三个AppDomain只好属于二个Process。

2、AppDomain vs 线程Thread

应当说两者之间没有关联,AppDomain出现的目标是隔绝,隔绝对象,而 Thread
是 Process中的一个实体、是程序试行流中的纤维单元,保存有眼下下令指针 和
寄存器集合,为线程切换提供恐怕。如果说有涉及的话,能够牵强的以为一个Thread能够动用五个AppDomain中的对象,3个AppDomain中得以接纳几个Thread.

三、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的基本配备单元,它可感到CLKoleos提供元数据等。

Assembly不能独立施行,它必须被加载到AppDomain中,然后由AppDomain创设程序集中的品类
及 对象。

八个Assembly可以被多少个AppDomain加载,一个AppDomain能够加载两个Assembly。

每一个AppDomain引用到某些项目标时候供给把相应的assembly在各自的AppDomain中开头化。因而,每一个AppDomain会单独保持贰个类的静态变量。

4、AppDomain vs 对象object
别的对象只好属于二个AppDomain,AppDomain用来隔绝对象。
同一应用程序域中的对象间接通讯、分裂应用程序域中的对象的通讯格局有三种:一种是跨应用程序域边界传输对象别本(通过类别化对目标开展隐式值封送完了),一种是利用代理交流消息。

主应用程序入口:

主应用程序入口:

二、创建 和 卸载AppDomain

前文已经证实了,大家得以在运营时动态的成立和卸载AppDomain,
有这样的辩论功底在、大家就足以热进级应用程序了 。

那就让我们来看一下如何创制和卸载AppDomain吧

创建:

                AppDomainSetup objSetup = new AppDomainSetup();                objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;                this.domain = AppDomain.CreateDomain("RemoteAppDomain", null, objSetup);

创办AppDomain的逻辑分外轻松:使用 AppDomain.CreateDomain
静态方法、传递了三个任意字符串 和AppDomainSetup 对象。

卸载:

              AppDomain.Unload(this.domain);

卸载就更轻松了一行代码化解:AppDomain.Unload 静态方法,参数就三个从前创立的AppDomain对象。

using Kernel.ServiceAgent;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.App
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("");

            using (ServiceManager<IObjcet> manager = new ServiceManager<IObjcet>()) 
            {
                string result = manager.Proxy.Put("apprun one");
                Console.WriteLine(result);
                Console.WriteLine("");
                Console.WriteLine("                         Thread AppDomain info                             ");
                Console.WriteLine(manager.CotrProxy.FriendlyName);
                Console.WriteLine(Thread.GetDomain().FriendlyName);
                Console.WriteLine(manager.CotrProxy.BaseDirectory);
                Console.WriteLine(manager.CotrProxy.ShadowCopyFiles);
                Console.WriteLine("");
            }

            Console.ReadLine();
        }
    }
}
using Kernel.ServiceAgent;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.App
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("");

            using (ServiceManager<IObjcet> manager = new ServiceManager<IObjcet>()) 
            {
                string result = manager.Proxy.Put("apprun one");
                Console.WriteLine(result);
                Console.WriteLine("");
                Console.WriteLine("                         Thread AppDomain info                             ");
                Console.WriteLine(manager.CotrProxy.FriendlyName);
                Console.WriteLine(Thread.GetDomain().FriendlyName);
                Console.WriteLine(manager.CotrProxy.BaseDirectory);
                Console.WriteLine(manager.CotrProxy.ShadowCopyFiles);
                Console.WriteLine("");
            }

            Console.ReadLine();
        }
    }
}

3、在新AppDomain中创造对象

上文已经说了创办AppDomain了,然则创制的新AppDomain却是不含有其他对象的,只是一个空壳子。那么什么样在新的AppDomain中创设对象呢?

this.remoteIPlugin = this.domain.CreateInstance("PluginDemo.NewDomain", "PluginDemo.NewDomain.Plugin").Unwrap() as IPlugin;

动用刚成立的AppDomain对象的实例化方法:this.domain.CreateInstance,传递了七个字符串,分别为assemblyName
和 typeName.

同时该措施的重载方法 和 相似功用的重载方法多达1七个。

成立新的行使程序域并且在新的行使程序域中调用透明朝理类:

创办新的应用程序域并且在新的利用程序域中调用透唐宋理类:

4、影象复制造进程序集

创办、卸载AppDomain都有、创设新对象也得以了,可是只要想做到热晋级,还有有个别小麻烦,那正是3个先后集被加载后会被锁定,那时候是力不从心对其打开更换的。

之所以就须求开发影象复制造进程序集成效,那样在卸载AppDomain后,把供给升级的应用程序集进行进步替换,然后再次创下设新的AppDomain就能够了。

开发影像复制造进度序集作用,需求在创设新的AppDomain时做两步简单的设定就可以:

                AppDomainSetup objSetup = new AppDomainSetup();                objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

          // 打开 影像复制程序集 功能                objSetup.ShadowCopyFiles = "true";                // 虽然此方法已经被标记为过时方法, msdn备注也提倡不使用该方法,                // 但是 以.net 4.0 + win10环境测试,还必须调用该方法 否则,即便卸载了应用程序域 dll 还是未被解除锁定                AppDomain.CurrentDomain.SetShadowCopyFiles();                this.domain = AppDomain.CreateDomain("RemoteAppDomain", null, objSetup);
using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class ServiceManager<T> : IDisposable where T : class
    {
        private AppDomain ctorProxy = null;

        /// <summary>
        /// 应用程序运行域容器
        /// </summary>
        public AppDomain CotrProxy
        {
            get { return ctorProxy; }
        }

        private T proxy = default(T);

        public T Proxy
        {
            get
            {
                if (proxy == null)
                {
                    proxy = (T)InitProxy(AssemblyPlugs);
                }
                return proxy;
            }
        }

        private string assemblyPlugs;

        /// <summary>
        /// 外挂插件程序集目录路径
        /// </summary>
        public string AssemblyPlugs
        {
            get {
                assemblyPlugs = ConfigHelper.GetVaule("PrivatePath");
                if (assemblyPlugs.Equals("")){
                    assemblyPlugs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
                }
                if (!Directory.Exists(assemblyPlugs)) 
                {
                    Directory.CreateDirectory(assemblyPlugs);
                }
                return assemblyPlugs;
            }
            set { assemblyPlugs = value; }
        }

        public ServiceManager()
        {
            if (proxy == null)
            {
                proxy = (T)InitProxy(AssemblyPlugs);
            }
        }

        private T InitProxy(string assemblyPlugs)
        {
            try
            {
                //AppDomain.CurrentDomain.SetShadowCopyFiles();
                //Get and display the friendly name of the default AppDomain.
                //string callingDomainName = Thread.GetDomain().FriendlyName;

                //Get and display the full name of the EXE assembly.
                //string exeAssembly = Assembly.GetEntryAssembly().FullName;
                //Console.WriteLine(exeAssembly);

                AppDomainSetup ads = new AppDomainSetup();
                ads.ApplicationName = "Shadow";

                //应用程序根目录
                ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

                //子目录(相对形式)在AppDomainSetup中加入外部程序集的所在目录,多个目录用分号间隔
                ads.PrivateBinPath = assemblyPlugs;
                //设置缓存目录
                ads.CachePath = ads.ApplicationBase;
                //获取或设置指示影像复制是打开还是关闭
                ads.ShadowCopyFiles = "true";
                //获取或设置目录的名称,这些目录包含要影像复制的程序集
                ads.ShadowCopyDirectories = ads.ApplicationBase;

                ads.DisallowBindingRedirects = false;
                ads.DisallowCodeDownload = true;

                ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

                //Create evidence for the new application domain from evidence of
                Evidence adevidence = AppDomain.CurrentDomain.Evidence;

                // Create the second AppDomain.
                ctorProxy = AppDomain.CreateDomain("AD #2", adevidence, ads);

                //Type.GetType("Kernel.TypeLibrary.MarshalByRefType").Assembly.FullName
                string assemblyName = Assembly.GetExecutingAssembly().GetName().FullName;
                //string assemblyName = typeof(MarshalByRefType).Assembly.FullName

                // Create an instance of MarshalByRefObject in the second AppDomain. 
                // A proxy to the object is returned.

                Console.WriteLine("CtorProxy:" + Thread.GetDomain().FriendlyName);

                //TransparentFactory factory = (IObjcet)ctorProxy.CreateInstance("Kernel.TypeLibrary",
               "Kernel.TypeLibrary.TransparentFactory").Unwrap();
                TransparentAgent factory = (TransparentAgent)ctorProxy.CreateInstanceAndUnwrap(assemblyName, 
                              typeof(TransparentAgent).FullName);

                Type meetType = typeof(T);
                string typeName = AssemblyHelper.CategoryInfo(meetType);

                object[] args = new object[0];
                string assemblyPath = ctorProxy.SetupInformation.PrivateBinPath;

                //IObjcet ilive = factory.Create(@"E:\Plug\Kernel.SimpleLibrary.dll", "Kernel.SimpleLibrary.PlugPut", args);
                T obj = factory.Create<T>(assemblyPath, typeName, args);

                return obj;
            }
            catch (System.Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 卸载应用程序域
        /// </summary>
        public void Unload()
        {
            try
            {
                if (ctorProxy != null)
                {
                    AppDomain.Unload(ctorProxy);
                    ctorProxy = null;
                }
            }
            catch(Exception)
            {
                throw;
            }
        }

        public void Dispose()
        {
            this.Unload();
        }
    }
}
using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class ServiceManager<T> : IDisposable where T : class
    {
        private AppDomain ctorProxy = null;

        /// <summary>
        /// 应用程序运行域容器
        /// </summary>
        public AppDomain CotrProxy
        {
            get { return ctorProxy; }
        }

        private T proxy = default(T);

        public T Proxy
        {
            get
            {
                if (proxy == null)
                {
                    proxy = (T)InitProxy(AssemblyPlugs);
                }
                return proxy;
            }
        }

        private string assemblyPlugs;

        /// <summary>
        /// 外挂插件程序集目录路径
        /// </summary>
        public string AssemblyPlugs
        {
            get {
                assemblyPlugs = ConfigHelper.GetVaule("PrivatePath");
                if (assemblyPlugs.Equals("")){
                    assemblyPlugs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
                }
                if (!Directory.Exists(assemblyPlugs)) 
                {
                    Directory.CreateDirectory(assemblyPlugs);
                }
                return assemblyPlugs;
            }
            set { assemblyPlugs = value; }
        }

        public ServiceManager()
        {
            if (proxy == null)
            {
                proxy = (T)InitProxy(AssemblyPlugs);
            }
        }

        private T InitProxy(string assemblyPlugs)
        {
            try
            {
                //AppDomain.CurrentDomain.SetShadowCopyFiles();
                //Get and display the friendly name of the default AppDomain.
                //string callingDomainName = Thread.GetDomain().FriendlyName;

                //Get and display the full name of the EXE assembly.
                //string exeAssembly = Assembly.GetEntryAssembly().FullName;
                //Console.WriteLine(exeAssembly);

                AppDomainSetup ads = new AppDomainSetup();
                ads.ApplicationName = "Shadow";

                //应用程序根目录
                ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

                //子目录(相对形式)在AppDomainSetup中加入外部程序集的所在目录,多个目录用分号间隔
                ads.PrivateBinPath = assemblyPlugs;
                //设置缓存目录
                ads.CachePath = ads.ApplicationBase;
                //获取或设置指示影像复制是打开还是关闭
                ads.ShadowCopyFiles = "true";
                //获取或设置目录的名称,这些目录包含要影像复制的程序集
                ads.ShadowCopyDirectories = ads.ApplicationBase;

                ads.DisallowBindingRedirects = false;
                ads.DisallowCodeDownload = true;

                ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

                //Create evidence for the new application domain from evidence of
                Evidence adevidence = AppDomain.CurrentDomain.Evidence;

                // Create the second AppDomain.
                ctorProxy = AppDomain.CreateDomain("AD #2", adevidence, ads);

                //Type.GetType("Kernel.TypeLibrary.MarshalByRefType").Assembly.FullName
                string assemblyName = Assembly.GetExecutingAssembly().GetName().FullName;
                //string assemblyName = typeof(MarshalByRefType).Assembly.FullName

                // Create an instance of MarshalByRefObject in the second AppDomain. 
                // A proxy to the object is returned.

                Console.WriteLine("CtorProxy:" + Thread.GetDomain().FriendlyName);

                //TransparentFactory factory = (IObjcet)ctorProxy.CreateInstance("Kernel.TypeLibrary",
               "Kernel.TypeLibrary.TransparentFactory").Unwrap();
                TransparentAgent factory = (TransparentAgent)ctorProxy.CreateInstanceAndUnwrap(assemblyName, 
                              typeof(TransparentAgent).FullName);

                Type meetType = typeof(T);
                string typeName = AssemblyHelper.CategoryInfo(meetType);

                object[] args = new object[0];
                string assemblyPath = ctorProxy.SetupInformation.PrivateBinPath;

                //IObjcet ilive = factory.Create(@"E:\Plug\Kernel.SimpleLibrary.dll", "Kernel.SimpleLibrary.PlugPut", args);
                T obj = factory.Create<T>(assemblyPath, typeName, args);

                return obj;
            }
            catch (System.Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 卸载应用程序域
        /// </summary>
        public void Unload()
        {
            try
            {
                if (ctorProxy != null)
                {
                    AppDomain.Unload(ctorProxy);
                    ctorProxy = null;
                }
            }
            catch(Exception)
            {
                throw;
            }
        }

        public void Dispose()
        {
            this.Unload();
        }
    }
}

五、简单的Demo

幸存1接口IPlugin:

美高梅开户网址 3美高梅开户网址 4

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Input;namespace PluginDemo{    public interface IPlugin    {        int GetInt();        string GetString();                object GetNonMarshalByRefObject();        Action GetAction();        List<string> GetList();    }}

接口 IPlugin

在此外的3个主次集中有其三个落到实处类 Plugin:

美高梅开户网址 5美高梅开户网址 6

using System;using System.Collections.Generic;using System.Linq;using System.Text;using PluginDemo;namespace PluginDemo.NewDomain{    /// <summary>    /// 支持跨应用程序域访问    /// </summary>    public class Plugin : MarshalByRefObject, IPlugin    {        // AppDomain被卸载后,静态成员的内存会被释放掉        private static int length;        /// <summary>        /// int 作为基础数据类型, 是持续序列化的.        /// <para>在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送)</para>        /// </summary>        /// <returns></returns>        public int GetInt()        {            length += new Random().Next(10000);            return length;        }        /// <summary>        /// string 作为特殊的class, 也是持续序列化的.        /// <para>在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送)</para>        /// </summary>        /// <returns></returns>        public string GetString()        {            return "iqingyu";        }        /// <summary>        /// 未继承 MarshalByRefObject 并且 不支持序列化 的 class, 是不可以跨AppDomain通信的,也就是说其他AppDomain是获取不到其对象的        /// </summary>        /// <returns></returns>        public object GetNonMarshalByRefObject()        {            return new NonMarshalByRefObject();        }        private NonMarshalByRefObjectAction obj = new NonMarshalByRefObjectAction();        /// <summary>        /// 委托,和 委托所指向的类型相关        /// <para>也就是说,如果其指向的类型支持跨AppDomain通信,那个其他AppDomain就可以获取都该委托, 反之,则不能获取到</para>        /// </summary>        /// <returns></returns>        public Action GetAction()        {            obj.Add();            obj.Add();            //obj.Add();            return obj.TestAction;        }        private List<string> list = new List<string>() { "A", "B" };        /// <summary>        /// List<T> 也是持续序列化的, 当然前提是T也必须支持跨AppDomain通信        /// <para>在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送)</para>        /// </summary>        /// <returns></returns>        public List<string> GetList()        {            return this.list;            // return new List<Action>() { this.GetAction() };        }    }}

实现类 Plugin

在其余的一个先后集中还有八个

美高梅开户网址 7美高梅开户网址 8

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace PluginDemo.NewDomain{    /// <summary>    /// 未继承 MarshalByRefObject,  不可以跨AppDomain交换消息    /// </summary>    public class NonMarshalByRefObject    {    }}

空类型 NonMarshalByRefObject

测试程序如下:

美高梅开户网址 9美高梅开户网址 10

using System;using System.Windows;using System.Diagnostics;using System.Runtime.Serialization.Formatters.Binary;namespace PluginDemo{    /// <summary>    /// MainWindow.xaml 的交互逻辑    /// </summary>    public partial class MainWindow : Window    {        private AppDomain domain;        private IPlugin remoteIPlugin;        public MainWindow()        {            InitializeComponent();        }        private void loadBtn_Click(object sender, RoutedEventArgs e)        {            try            {                unLoadBtn_Click(sender, e);                this.txtBlock.Text = string.Empty;                // 在新的AppDomain中加载 RemoteCamera 类型                AppDomainSetup objSetup = new AppDomainSetup();                objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;                objSetup.ShadowCopyFiles = "true";                // 虽然此方法已经被标记为过时方法, msdn备注也提倡不使用该方法,                // 但是 以.net 4.0 + win10环境测试,还必须调用该方法 否则,即便卸载了应用程序域 dll 还是未被解除锁定                AppDomain.CurrentDomain.SetShadowCopyFiles();                this.domain = AppDomain.CreateDomain("RemoteAppDomain", null, objSetup);                this.remoteIPlugin = this.domain.CreateInstance("PluginDemo.NewDomain", "PluginDemo.NewDomain.Plugin").Unwrap() as IPlugin;                this.txtBlock.AppendText("创建AppDomain成功\r\n\r\n");            }            catch (Exception ex)            {                this.txtBlock.AppendText(ex.Message);                this.txtBlock.AppendText("\r\n\r\n");            }        }        private void unLoadBtn_Click(object sender, RoutedEventArgs e)        {            if (this.remoteIPlugin != null)            {                this.remoteIPlugin = null;            }            if (this.domain != null)            {                AppDomain.Unload(this.domain);                this.domain = null;                this.txtBlock.AppendText("卸载AppDomain成功\r\n\r\n");            }        }        private void invokeBtn_Click(object sender, RoutedEventArgs e)        {            if (this.remoteIPlugin == null)                return;            this.txtBlock.AppendText($"GetInt():{ this.remoteIPlugin.GetInt().ToString()}\r\n");            this.txtBlock.AppendText($"GetString():{ this.remoteIPlugin.GetString().ToString()}\r\n");            try            {                this.remoteIPlugin.GetNonMarshalByRefObject();            }            catch (Exception ex)            {                this.txtBlock.AppendText($"GetNonMarshalByRefObject():{ ex.Message}\r\n");                if (Debugger.IsAttached)                {                    Debugger.Break();                }            }                  }    }}

测试程序

按测试程序代码试行,先Load AppDomain, 然后 Access Other Member,
此时会发现并发了老大,大约内容如下:

创建AppDomain成功

GetInt():1020
GetString():iqingyu
GetNon马尔斯halByRefObject():程序集“Plugin德姆o.NewDomain,
Version=一.0.0.0, Culture=neutral,
PublicKeyToken=null”中的类型“Plugin德姆o.NewDomain.Non马尔斯halByRefObject”未标识为可体系化。

是由于Plugin德姆o.NewDomain.Non马尔斯halByRefObject 这么些项目未标志可体系化
而引发的。 那么那种景观下和体系化又有哪些关联吗?

请继续往下看。

制造应用程序代理类:

始建应用程序代理类:

6、AppDomain间的靶子通讯

前文说过了,AppDomain 是用来隔绝对象的,AppDomain
之间的目标是无法随心所欲通讯的,那一点在 MSND的备注 中有一段描述:

data-source=”An application domain is a partition in an operating system process where one or more applications reside.”>应用程序域是3个操作系统进度中二个或多个应用程序所驻留的分区。 data-gu=””
data-source=”Objects in the same application domain communicate directly.”>同一应用程序域中的对象直接通讯。 data-gu=””
data-source=”Objects in different application domains communicate either by transporting copies of objects across application domain boundaries, or by using a proxy to exchange messages.”>差别接纳程序域中的对象的通讯形式有二种:1种是跨应用程序域边界传输对象别本,一种是行使代理调换消息。

data-source=”<span class="selflink">马尔斯halByRefObject is the base class for objects that communicate across application domain boundaries by exchanging messages using a proxy.”>马尔斯halByRefObject是因此接纳代理沟通新闻来跨应用程序域边界举办通信的目标的基类。 data-gu=””
data-source=”Objects that do not inherit from <span class="selflink">马尔斯halByRefObject are implicitly marshal by value.”>不是从马尔斯halByRefObject承接的对象依据值隐式封送。 data-gu=””
data-source=”When a remote application references a marshal by value object, a copy of the object is passed across application domain boundaries.”>当远程应用程序引用依据值封送的靶龙时,将跨应用程序域边界传递该目的的别本。

data-source=”<span class="selflink">MarshalByRefObject objects are accessed directly within the boundaries of the local application domain.”>MarshalByRefObject对象在本地使用程序域的疆界内可径直访问。 data-gu=””
data-source=”The first time an application in a remote application domain accesses a <span class="selflink">马尔斯halByRefObject, a proxy is passed to the remote application.”>远程应用程序域中的应用程序第贰次访问马尔斯halByRefObject时,会向该远程应用程序传递代理。 data-gu=””
data-source=”Subsequent calls on the proxy are marshaled back to the object residing in the local application domain.”>对该代理前边的调用将封送回驻留在本地使用程序域中的对象。

data-source=”Types must inherit from <span class="selflink">马尔斯halByRefObject when the type is used across application domain boundaries, and the state of the object must not be copied because the members of the object are not usable outside the application domain where they were created.”>当跨应用程序域边界使用项目时,类型必须是从马尔斯halByRefObject承继的,而且由于目的的分子在开立它们的利用程序域之外不能够选择,所以不得复制对象的状态。

约等于说AppDomain间的目的通信有三种办法:壹种是后续马尔斯halByRefObject
,具备使用代理调换音信的手艺,别的一种是接纳体系化、传递对象别本。

先是种:表现情势上来讲,传递的是目的引用。 第三种传递的是目的别本,也等于说不是同三个目的。

也正由此,由于PluginDemo.NewDomain.Non马尔斯halByRefObject
即不是马尔斯halByRefObject 的子类,也不得以开始展览体系化,故
不可在多少个分裂的AppDomain间通讯。

而地点的不得了,则是由体系化Plugin德姆o.NewDomain.Non马尔斯halByRefObject
对象战败致使的万分。

假如1个项目 马尔斯halByRefObject的子类 并且 SerializableAttribute,
则该项目标目的无法被此外AppDomain中的对象所走访,
当然这种景况下的该类型对象中的成员也不容许被访问到了

反之,则足以被其余AppDomain中的对象所访问

1旦一个类别 马尔斯halByRefObject的子类, 则跨AppDomain所收获的是
(为了好理演说成靶子引用,实质为代理)

假设一个品种 SerializableAttribute, 则跨AppDomain所收获的是
,该别本是因此类别化实行值封送的

那儿传递到此外AppDomain 中的对象 和 当前目的已经不是同一个对象了

若是三个品种 马尔斯halByRefObject的子类 并且 SerializableAttribute,
则 马尔斯halByRefObject 的事先级越来越高

除此以外:.net 基本项目 、string 类型、 List<T>
等品种,纵然尚无标志SerializableAttribute,
然而她们依然故我得以种类化。也便是说那一个品种都足以在差异的AppDomain之间通信,只是传递的都以目的别本。

using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class TransparentAgent : MarshalByRefObject
    {
        private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

        public TransparentAgent() { }

        /// <summary> Factory method to create an instance of the type whose name is specified,
        /// using the named assembly file and the constructor that best matches the specified parameters. </summary>
        /// <param name="assemblyFile"> The name of a file that contains an assembly where the type named typeName is sought. </param>
        /// <param name="typeName"> The name of the preferred type. </param>
        /// <param name="constructArgs"> An array of arguments that match in number, order,
     /// and type the parameters of the constructor to invoke, or null for default constructor. </param>
        /// <returns> The return value is the created object represented as IObjcet. </returns>
        public IObjcet Create(string assemblyFile, string typeName, object[] args)
        {
            return (IObjcet)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }

        public T Create<T>(string assemblyPath, string typeName, object[] args)
        {
            string assemblyFile = AssemblyHelper.LoadAssemblyFile(assemblyPath, typeName);
            return (T)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }
    }
}
using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class TransparentAgent : MarshalByRefObject
    {
        private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

        public TransparentAgent() { }

        /// <summary> Factory method to create an instance of the type whose name is specified,
        /// using the named assembly file and the constructor that best matches the specified parameters. </summary>
        /// <param name="assemblyFile"> The name of a file that contains an assembly where the type named typeName is sought. </param>
        /// <param name="typeName"> The name of the preferred type. </param>
        /// <param name="constructArgs"> An array of arguments that match in number, order,
     /// and type the parameters of the constructor to invoke, or null for default constructor. </param>
        /// <returns> The return value is the created object represented as IObjcet. </returns>
        public IObjcet Create(string assemblyFile, string typeName, object[] args)
        {
            return (IObjcet)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }

        public T Create<T>(string assemblyPath, string typeName, object[] args)
        {
            string assemblyFile = AssemblyHelper.LoadAssemblyFile(assemblyPath, typeName);
            return (T)Activator.CreateInstanceFrom(assemblyFile, typeName, false, bfi, null, args, null, null).Unwrap();
        }
    }
}

七、完整的Demo

一体化的德姆o作者已上传至Github, :

PluginDemo

PluginDemo.NewDomain

七个项目为全部的德姆o

装有涉及到需求动态加载或释放的资源,都急需放在代理类中张开操作,唯有在此代理类中张开托管的代码才是属于新建的施用程序域的操作。

富有关乎到必要动态加载或自由的能源,都亟需放在代理类中举行操作,唯有在此代理类中开始展览托管的代码才是属于新建的选拔程序域的操作。

using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class AssemblyHelper
    {
        /// <summary>
        /// 获取泛型类中指定属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static string CategoryInfo(Type meetType)
        {
            object[] attrList = meetType.GetCustomAttributes(typeof(CategoryInfoAttribute), false);
            if (attrList != null)
            {
                CategoryInfoAttribute categoryInfo = (CategoryInfoAttribute)attrList[0];
                return categoryInfo.Category;
            }
            return "";
        }

        public static string LoadAssemblyFile(string assemblyPlugs, string typeName)
        {
            string path = string.Empty;
            DirectoryInfo d = new DirectoryInfo(assemblyPlugs);
            foreach (FileInfo file in d.GetFiles("*.dll"))
            {
                Assembly assembly = Assembly.LoadFile(file.FullName);
                Type type = assembly.GetType(typeName, false);
                if (type != null)
                {
                    path = file.FullName;
                }
            }
            return path;
        }
    }
}
using Kernel.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Kernel.ServiceAgent
{
    public class AssemblyHelper
    {
        /// <summary>
        /// 获取泛型类中指定属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static string CategoryInfo(Type meetType)
        {
            object[] attrList = meetType.GetCustomAttributes(typeof(CategoryInfoAttribute), false);
            if (attrList != null)
            {
                CategoryInfoAttribute categoryInfo = (CategoryInfoAttribute)attrList[0];
                return categoryInfo.Category;
            }
            return "";
        }

        public static string LoadAssemblyFile(string assemblyPlugs, string typeName)
        {
            string path = string.Empty;
            DirectoryInfo d = new DirectoryInfo(assemblyPlugs);
            foreach (FileInfo file in d.GetFiles("*.dll"))
            {
                Assembly assembly = Assembly.LoadFile(file.FullName);
                Type type = assembly.GetType(typeName, false);
                if (type != null)
                {
                    path = file.FullName;
                }
            }
            return path;
        }
    }
}

读取配置文件音讯:

读取配置文件音信:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace Kernel.ServiceAgent
{
    public class ConfigHelper
    {
        public static string GetVaule(string configName)
        {
            string configVaule = ConfigurationManager.AppSettings[configName];
            if (configVaule != null && configVaule != "")
            {
                return configVaule.ToString();
            }
            return "";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace Kernel.ServiceAgent
{
    public class ConfigHelper
    {
        public static string GetVaule(string configName)
        {
            string configVaule = ConfigurationManager.AppSettings[configName];
            if (configVaule != null && configVaule != "")
            {
                return configVaule.ToString();
            }
            return "";
        }
    }
}

布局文件有关布置音信:

配备文件有关配置音讯:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <appSettings>
      <add key="PrivatePath" value="E:\Plugins"/>
    </appSettings>
</configuration>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <appSettings>
      <add key="PrivatePath" value="E:\Plugins"/>
    </appSettings>
</configuration>

制造接口音信:

始建接口音信:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    [CategoryInfo("Kernel.SimpleLibrary.PlugPut", "")]
    public interface IObjcet
    {
        void Put();

        string Put(string plus);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    [CategoryInfo("Kernel.SimpleLibrary.PlugPut", "")]
    public interface IObjcet
    {
        void Put();

        string Put(string plus);
    }
}

开创接口自定义属性:

创办接口自定义属性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    /// <summary>
    /// 设置接口实现类自定义标注属性
    /// </summary>
    /// 
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
    public class CategoryInfoAttribute : Attribute
    {
        public string Category { get; set; }

        public string Describtion { get; set; }

        /// <summary>
        /// 设置实现类自定义标注属性
        /// </summary>
        /// <param name="category"></param>
        /// <param name="describtion"></param>
        public CategoryInfoAttribute(string category, string describtion)
        {
            this.Category = category;
            this.Describtion = describtion;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kernel.Interface
{
    /// <summary>
    /// 设置接口实现类自定义标注属性
    /// </summary>
    /// 
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
    public class CategoryInfoAttribute : Attribute
    {
        public string Category { get; set; }

        public string Describtion { get; set; }

        /// <summary>
        /// 设置实现类自定义标注属性
        /// </summary>
        /// <param name="category"></param>
        /// <param name="describtion"></param>
        public CategoryInfoAttribute(string category, string describtion)
        {
            this.Category = category;
            this.Describtion = describtion;
        }
    }
}

成立承袭至IObjcet接口带有具体操作的贯彻类:

开创承继至IObjcet接口带有具体操作的兑现类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kernel.Interface;

namespace Kernel.SimpleLibrary
{
    [Serializable]
    public class PlugPut : MarshalByRefObject, IObjcet
    {

        private string plugName = "my plugName value is default!";

        public string PlugName
        {
            get { return plugName; }
            set { plugName = value; }
        }

        public PlugPut() { }


        public PlugPut(string plusName) 
        {
            this.PlugName = plusName;
        }

        public void Put()
        {
            Console.WriteLine("Default plug value is:" + plugName);
        }

        public string Put(string plus)
        {
            Console.WriteLine("Put plus value is:" + plus);
            return ("-------------------- PlugPut result info is welcome -------------------------");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kernel.Interface;

namespace Kernel.SimpleLibrary
{
    [Serializable]
    public class PlugPut : MarshalByRefObject, IObjcet
    {

        private string plugName = "my plugName value is default!";

        public string PlugName
        {
            get { return plugName; }
            set { plugName = value; }
        }

        public PlugPut() { }


        public PlugPut(string plusName) 
        {
            this.PlugName = plusName;
        }

        public void Put()
        {
            Console.WriteLine("Default plug value is:" + plugName);
        }

        public string Put(string plus)
        {
            Console.WriteLine("Put plus value is:" + plus);
            return ("-------------------- PlugPut result info is welcome -------------------------");
        }
    }
}

  承袭至IObjcet接口带有具体操作的兑现类,正是属于须求动态替换更新的程序集,所以最棒将其编译在3个独立的主次集中,插件目录在布署文件中可陈设,示例中放置在E:\Plugins
目录下,示例中代码最终将生成 Kernel.SimpleLibrary.DLL ,最后将编写翻译好的先后集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运维后将加载此程序集,加载完成运转落成后并释放此程序集。

  传承至IObjcet接口带有具体操作的兑现类,就是属于供给动态替换更新的程序集,所以最好将其编写翻译在多少个独门的顺序集中,插件目录在配备文件中可布署,示例中放置在E:\Plugins
目录下,示例中代码最终将生成 Kernel.SimpleLibrary.DLL ,最后将编写翻译好的顺序集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运转后将加载此程序集,加载完成运营实现后并释放此程序集。

  以下两句较为重要,最棒设置一下,不设置的结局临时并未有品味

  以下两句较为主要,最棒设置一下,不设置的结果一时半刻髦未品味

  //获取或安装提示印象复制是开采依旧关闭
  ads.ShadowCopyFiles = “true”;
  //获取或安装目录的称呼,这么些目录包括要影像复制的主次集
  ads.ShadowCopyDirectories = ads.ApplicationBase;

  //获取或设置提示影象复制是张开照旧关闭
  ads.ShadowCopyFiles = “true”;
  //获取或设置目录的称谓,那些目录包涵要影象复制的次序集
  ads.ShadowCopyDirectories = ads.ApplicationBase;

  当程序运维起来后,程序集加载之后会在设置的运用程序域缓存目录中复制一份程序集的别本,然后运转别本中的程序集,释放掉自家加载的次第集。以上示例中会在主程序目录下生成1个Shadow
目录,此目录下富含了先后集的别本文件。

  当程序运维起来后,程序集加载之后会在安装的选取程序域缓存目录中复制1份程序集的别本,然后运转别本中的程序集,释放掉自家加载的主次集。以上示例中会在主程序目录下生成三个Shadow
目录,此目录下富含了先后集的别本文件。

小节:

小节:

  假若在另2个AppDomain
中加载程序集,然后拿走Type,最后在主AppDomain中应用CreateInstance中的Type重载创制对象,结果会是Type所属的程序集会被投入到当下AppDomain中,然后Type的实例会在脚下AppDomain中开创。

  假诺在另七个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中利用CreateInstance中的Type重载创造对象,结果会是Type所属的主次集会被投入到当下AppDomain中,然后Type的实例会在脚下AppDomain中开创。

  只有接轨至 马尔斯halByRefObject
的透秦代理类本领够进行跨域操作。**

  只有继承至 马尔斯halByRefObject
的晶莹代理类技艺够举办跨域操作。**

  所以供给在继续至 马尔斯halByRefObject
的透汉代理类中实行有关操作然后归来给主应用程序域,唯有在代理类中张开的代码操作才是属于新建的采取程序域。不然别的运转代理类以外的代码都以属于主应用程序域。

  所以供给在再而三至 马尔斯halByRefObject
的晶莹代理类中进行相关操作然后赶回给主应用程序域,唯有在代理类中张开的代码操作才是属于新建的接纳程序域。不然其余运转代理类以外的代码都是属于主应用程序域。

  此章节只是讲解了先后集动态加载或卸载热插拔的兑现格局,有关AppDomain
和 AppDomainSetup 具体音讯能够参照MSDN上边的文档。

  此章节只是讲明了先后集动态加载或卸载热插拔的得以达成格局,有关AppDomain
和 AppDomainSetup 具体音信能够参见MSDN下面的文档。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图