NET插件技术,应用程序域完毕程序集动态卸载或加载

By admin in 4858.com on 2019年4月4日

  AppDomain 表示应用程序域,它是叁个应用程序在其间实施的单身环境。各种应用程序只有三个主应用程序域,但是三个应用程序可以成立多少个子应用程序域。

C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载,

  AppDomain 表示应用程序域,它是3个应用程序在里面实施的单身环境。种种应用程序唯有三个主应用程序域,不过3个应用程序能够成立多少个子应用程序域。

  因而得以由此 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.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.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
目录,此目录下富含了先后集的副本文件。

小节:

  假如在另三个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中选择CreateInstance中的Type重载创设对象,结果会是Type所属的次序集会被出席到日前AppDomain中,然后Type的实例会在最近AppDomain中开创。

  只有持续至 马尔斯halByRefObject
的晶莹代理类才能够举办跨域操作。**

  所以必要在三番5次至 马尔斯halByRefObject
的晶莹代理类中展开连锁操作然后回到给主应用程序域,唯有在代理类中进行的代码操作才是属于新建的运用程序域。不然其余运维代理类以外的代码都以属于主应用程序域。

  此章节只是讲解了先后集动态加载或卸载热插拔的落实格局,有关AppDomain
和 AppDomainSetup 具体音信能够参考MSDN下边包车型大巴文书档案。

通过 AppDomain
应用程序域达成程序集动态卸载或加载,
AppDomain表示应用程序域,它是三个应用程序在里边进行的独门环境。每种应用程序…

  AppDomain 表示应用程序域,它是八个应用程序在中间实施的独门环境。各样应用程序唯有1个主应用程序域,可是多个应用程序能够创设多少个子应用程序域。

前日说一说.NET 中的插件技术,即
应用程序热升级。在诸多气象下、大家期望用户对应用程序的升级是无感知的,并且尽量不封堵用户操作的。

  因而可以通过 AppDomain
创建新的施用程序域,在新创立的子应用程序域中加载执行程序集并且在实施完结后刑释程序集财富,来达成系统在运作状态下,程序集的动态加载或卸载,从而达到系统运转中先后集热更新的目标。

  因而能够透过 AppDomain
创造新的选拔程序域,在新创立的子应用程序域中加载执行程序集并且在履行实现后释放程序集财富,来实现系统在运营意况下,程序集的动态加载或卸载,从而达到系统运营中先后集热更新的指标。

即便如此在Web 可能WebAPI上,由于多点的存在能够各个停用单点举办系统升级,而不影响总体服务。可是客户端却不能够如此做,终归用户直接在利用着。

  所谓应用程序域,.Net引入的两个概念,指的是1种境界,它标识了代码的运营范围,在其间发生的别的表现,包罗越发都不会影响到其它应用程序域,起到平安隔断的效应。也得以看作是2个轻量级的长河。

  所谓应用程序域,.Net引入的三个定义,指的是壹种境界,它标识了代码的周转范围,在里面产生的任何表现,包蕴特别都不会影响到别的应用程序域,起到平安隔绝的成效。也足以用作是多个轻量级的长河。

那么有未有1种情势,能够在用户无感知的图景下(即、不鸣金收兵进程的情状下)对客户端进行进步吗?

一个进程能够包括四个使用程序域,种种域之间相互独立。如下是3个.net经过的咬合(图片来自网络)

一个进程能够涵盖多少个使用程序域,各类域之间交互独立。如下是3个.net历程的组合(图片源于网络)

答案是迟早的,
这就是本身今日想说的插件技术、能够对应用程序举办热升级。当然那种措施也一致适用于
ASP.NET ,

4858.com 1

4858.com 2

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

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

NET插件技术,应用程序域完毕程序集动态卸载或加载。以下为任何原理的贯彻代码

壹、应用程序域AppDomain

在介绍插件技术以前、大家要求先领会部分基础性的知识,第贰个正是行使程序域AppDomain.

操作系统和平运动行时环境1般会在应用程序间提供某种格局的隔断。例如,Windows
使用进度来隔离应用程序。为保障在二个应用程序中运营的代码不会对其余不相干的应用程序产生不良影响,那种隔开是少不了的。那种隔绝可以为运用程序域提供安全性、可信赖性,
并且为卸载程序集提供了说不定。


.NET中接纳程序域AppDomain是CL昂科雷的周转单元,它能够加载应用程序集Assembly、创造对象以及履行顺序。

在 CL中华V里、AppDomain正是用来贯彻代码隔绝的,每多个AppDomain能够单独成立、运营、卸载。

关于AppDomain中的未处理卓殊:

比方私下认可AppDomain监听了UnhandledException
事件,任何线程的其它未处理相当都会吸引该事件,无论线程是从哪个AppDomain中初露的。

只要多少个线程初阶于四个已经济监察听了UnhandledException事件的 app domain,
那么该事件将在那个app domain 中掀起。

要是那些app domian 不是默许的app domain, 并且 私下认可 app domain
中也监听了UnhandledException 事件, 那么 该事件将会在四个app domain
中吸引。

CLHighlander启用时,会创立三个暗许的AppDomain,程序的入口点正是在那些暗中同意的AppDomain中实践。

AppDomain是能够在运转时展开动态的创导和卸载的,正因如此,才为插件技术提供了基础(注:应用程序集和档次是无法卸载的,只好卸载整个AppDomain)。

AppDomain和其余概念之间的涉嫌

1、AppDomain vs 进程Process

AppDomain被创立在Process中,四个Process内足以有多少个AppDomain。一个AppDomain只可以属于一个Process。

2、AppDomain vs 线程Thread

有道是说两者之间未有关联,AppDomain出现的指标是与世隔膜,隔开对象,而 Thread
是 Process中的二个实体、是程序执行流中的小小单元,保存有方今下令指针 和
寄存器集合,为线程切换提供只怕。假如说有涉及的话,能够牵强的认为3个Thread能够应用多少个AppDomain中的对象,三个AppDomain中得以利用五个Thread.

三、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的为主配置单元,它能够为CL锐界提供元数据等。

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 静态方法,参数就3个在此之前创造的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();
        }
    }
}

叁、在新AppDomain中成立对象

上文已经说了创立AppDomain了,可是创制的新AppDomain却是不带有其他对象的,只是二个空壳子。那么哪些在新的AppDomain中创立对象呢?

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

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

再者该措施的重载方法 和 相似功用的重载方法多达二13个。

创制新的应用程序域并且在新的利用程序域中调用透清代理类:

开立异的运用程序域并且在新的运用程序域中调用透西汉理类:

4、影象复制造进程序集

开创、卸载AppDomain都有、创立新对象也能够了,不过只要想做到热升级,还有1些小麻烦,那就是2个顺序集被加载后会被锁定,那时候是力不从心对其开始展览改动的。

4858.com,因而就供给开拓影像复制造进程序集功效,这样在卸载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

幸存一接口IPlugin:

4858.com 34858.com 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

在此外的三个先后集中有其二个贯彻类 Plugin:

4858.com 54858.com 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

在此外的1个顺序集中还有三个

4858.com 74858.com 8

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

空类型 NonMarshalByRefObject

测试程序如下:

4858.com 94858.com 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的备注 中有1段描述:

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.”>MarshalByRefObject是透过动用代理交流信息来跨应用程序域边界进行通讯的对象的基类。 data-gu=””
data-source=”Objects that do not inherit from <span class="selflink">马尔斯halByRefObject are implicitly marshal by value.”>不是从MarshalByRefObject继承的靶子依照值隐式封送。 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">马尔斯halByRefObject 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
,拥有使用代理沟通新闻的力量,其它壹种是选拔体系化、传递对象副本。

率先种:表现情势上的话,传递的是目的引用。 第一种传递的是指标副本,也正是说不是同多少个对象。

也正就此,由于Plugin德姆o.NewDomain.Non马尔斯halByRefObject
即不是马尔斯halByRefObject 的子类,也无法实行种类化,故
不可在七个例外的AppDomain间通讯。

而地点的10分,则是由体系化PluginDemo.NewDomain.Non马尔斯halByRefObject
对象失败致使的不胜。

壹旦2个档次 马尔斯halByRefObject的子类 并且 SerializableAttribute,
则该类型的对象不能够被此外AppDomain中的对象所访问,
当然那种情景下的该项目对象中的成员也不也许被访问到了

相反,则能够被其余AppDomain中的对象所走访

假设三个门类 马尔斯halByRefObject的子类, 则跨AppDomain所获取的是
(为了好理解说成靶子引用,实质为代理)

一旦2个种类 SerializableAttribute, 则跨AppDomain所获取的是
,该副本是透过种类化实行值封送的

此刻传递到其它AppDomain 中的对象 和 当前目的已经不是同3个对象了

要是3个体系 马尔斯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

多个类别为完整的Demo

抱有关乎到供给动态加载或释放的财富,都要求放在代理类中举行操作,只有在此代理类中开始展览托管的代码才是属于新建的选用程序域的操作。

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

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接口带有具体操作的落实类,正是属于须求动态替换更新的程序集,所以最佳将其编写翻译在一个独立的顺序集中,插件目录在配置文件中可配备,示例中放置在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;

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

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

小节:

小节:

  假使在另二个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地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有