AppDomain 表示应用程序域,它是3个应用程序在里边施行的独自情状。每种应用程序只有贰个主应用程序域,然则一个应用程序能够创立多个子应用程序域。

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

  AppDomain 表示应用程序域,它是二个应用程序在中间进行的单独情形。每一种应用程序只有二个主应用程序域,可是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 "";
        }
    }
}

【金沙注册送58】选拔程序域完毕程序集动态卸载或加载,NET插件才干。配置文件有关配置消息:

<?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
目录,此目录下富含了程序集的别本文件。

金沙注册送58,小节:

  假若在另贰个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中接纳CreateInstance中的Type重载创制对象,结果会是Type所属的先后集会被投入到日前AppDomain中,然后Type的实例会在当前AppDomain中开创。

  只有一连至 马尔斯halByRefObject
的透南陈理类才具够进行跨域操作。**

  所以要求在此起彼伏至 马尔斯halByRefObject
的晶莹代理类中开始展览有关操作然后回来给主应用程序域,只有在代理类中进行的代码操作才是属于新建的接纳程序域。不然别的运营代理类以外的代码都是属于主应用程序域。

  此章节只是批注了程序集动态加载或卸载热插拔的落到实处格局,有关AppDomain
和 AppDomainSetup 具体音讯能够参见MSDN下面的文书档案。

通过 AppDomain
应用程序域得以完毕程序集动态卸载或加载,
AppDomain表示应用程序域,它是3个应用程序在其间施行的独立情形。每个应用程序…

  AppDomain 表示应用程序域,它是一个应用程序在中间实行的单身情况。每一种应用程序唯有1个主应用程序域,然而八个应用程序可以创建多少个子应用程序域。

前几日说壹说.NET 中的插件技艺,即
应用程序热晋级。在众多状态下、我们愿意用户对应用程序的晋级是无感知的,并且尽量不封堵用户操作的。

  因而得以经过 AppDomain
成立新的利用程序域,在新创设的子应用程序域中加载执行程序集并且在实践完成后放走程序集能源,来贯彻系统在运作情状下,程序集的动态加载或卸载,从而达到系统运维中等射程序集热更新的目标。

  因而得以经过 AppDomain
创设新的行使程序域,在新创立的子应用程序域中加载实践程序集并且在实践达成后释放程序集能源,来促成系统在运行意况下,程序集的动态加载或卸载,从而抵达系统运作中先后集热更新的目标。

固然在Web 或者WebAPI上,由于多点的存在能够每一个停用单点举行系统进级,而不影响整个服务。不过客户端却无法如此做,毕竟用户一直在行使着。

  所谓应用程序域,.Net引进的1个概念,指的是一种境界,它标记了代码的周转范围,在内部爆发的其它表现,包括尤其都不会影响到此外应用程序域,起到平安隔开的功能。也得以作为是三个轻量级的进度。

  所谓应用程序域,.Net引进的二个概念,指的是1种境界,它标记了代码的运作范围,在里边产生的别的表现,蕴涵尤其都不会影响到别的使用程序域,起到平安隔开的意义。也得以用作是3个轻量级的经过。

那便是说有未有一种情势,能够在用户无感知的状态下(即、不鸣金收兵进程的意况下)对客户端举行升高吗?

二个经过能够分包七个利用程序域,各种域之间互相独立。如下是一个.net进程的整合(图片来源网络)

3个进程能够分包八个利用程序域,各样域之间相互独立。如下是二个.net经过的组成(图片来自互连网)

答案是毫无疑问的,
那正是小编明天想说的插件才能、能够对应用程序实行热进级。当然那种情势也如出一辙适用于
ASP.NET ,

金沙注册送58 1

金沙注册送58 2

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

以下为全数原理的贯彻代码

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

1、应用程序域AppDomain

在介绍插件技艺在此之前、大家须求先领悟一些基础性的文化,第四个正是运用程序域AppDomain.

操作系统和平运动行时情形一般会在应用程序间提供某种情势的割裂。比如,Windows
使用进程来隔开应用程序。为保障在2个应用程序中运行的代码不会对其他不相干的应用程序爆发不良影响,那种隔开是须求的。那种隔绝可感觉利用程序域提供安全性、可信性,
并且为卸载程序集提供了大概。


.NET中央银行使程序域AppDomain是CLLX570的运转单元,它能够加载应用程序集Assembly、成立对象以及施行顺序。

在 CL汉兰达里、AppDomain便是用来落到实处代码隔开的,每三个AppDomain能够独立成立、运转、卸载。

有关AppDomain中的未管理分外:

借使暗许AppDomain监听了UnhandledException
事件,任何线程的别样未管理分外都会抓住该事件,无论线程是从哪个AppDomain中早先的。

如果叁个线程早先于贰个业已监听了UnhandledException事件的 app domain,
那么该事件就要那几个app domain 中吸引。

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

CLQX56启用时,会创设三个私下认可的AppDomain,程序的入口点正是在那几个暗中认可的AppDomain中试行。

AppDomain是足以在运营时张开动态的创导和卸载的,正因如此,才为插件技巧提供了根基(注:应用程序集和项目是无法卸载的,只好卸载整个AppDomain)。

AppDomain和其它概念之间的关系

1、AppDomain vs 进程Process

AppDomain被创制在Process中,1个Process内足以有几个AppDomain。1个AppDomain只可以属于3个Process。

2、AppDomain vs 线程Thread

有道是说两者之间未有涉嫌,AppDomain现身的目的是割裂,隔开分离对象,而 Thread
是 Process中的二个实体、是程序推行流中的蝇头单元,保存有目前下令指针 和
寄存器会集,为线程切换提供大概。假若说有关系的话,能够牵强的以为1个Thread能够运用几个AppDomain中的对象,一个AppDomain中得以行使三个Thread.

3、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的中央配置单元,它可以为CL福特Explorer提供元数据等。

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

2个Assembly能够被八个AppDomain加载,叁个AppDomain能够加载多个Assembly。

每一个AppDomain引用到有些项目标时候必要把相应的assembly在分别的AppDomain中初步化。因而,每一种AppDomain会单独保持3个类的静态变量。

4、AppDomain vs 对象object
别的对象只好属于二个AppDomain,AppDomain用来隔离对象。
同一应用程序域中的对象直接通讯、区别应用程序域中的对象的通讯方式有二种:一种是跨应用程序域边界传输对象别本(通过连串化对目的开始展览隐式值封送完了),1种是采用代理交流音讯。

主应用程序入口:

主应用程序入口:

二、创建 和 卸载AppDomain

前文已经表达了,大家能够在运行时动态的创导和卸载AppDomain,
有那样的论争基础在、大家就能够热进级应用程序了 。

那就让大家来看一下哪些创制和卸载AppDomain吧

创建:

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

开创AppDomain的逻辑1贰分简单:使用 AppDomain.CreateDomain
静态方法、传递了3个自便字符串 和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();
        }
    }
}

叁、在新AppDomain中创制对象

上文已经说了创办AppDomain了,然则成立的新AppDomain却是不包括其余对象的,只是二个空壳子。那么怎样在新的AppDomain中成立对象呢?

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

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

还要该方法的重载方法 和 相似成效的重载方法多达二十一个。

成立新的施用程序域并且在新的施用程序域中调用透唐代理类:

创立新的使用程序域并且在新的使用程序域中调用透西楚理类:

肆、影象复制造进程序集

始建、卸载AppDomain都有、创制新目标也足以了,可是一旦想做到热升级,还有少数小麻烦,那正是三个主次集被加载后会被锁定,那时候是力不从心对其举行修改的。

由此就要求展开影象复制造进程序集功效,那样在卸载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:

金沙注册送58 3金沙注册送58 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:

金沙注册送58 5金沙注册送58 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

在其余的3个主次聚焦还有2个

金沙注册送58 7金沙注册送58 8

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

空类型 NonMarshalByRefObject

测试程序如下:

金沙注册送58 9金沙注册送58 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,
此时会发掘并发了11分,差不离内容如下:

创建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 那几个类型未标志可种类化
而吸引的。 那么那种气象下和种类化又有啥样关系啊?

请继续往下看。

创设应用程序代理类:

创办应用程序代理类:

陆、AppDomain间的靶子通讯

前文说过了,AppDomain 是用来隔绝对象的,AppDomain
之间的目的是无法率性通讯的,那点在 MSND的备注 中有1段描述:

data-source=”An application domain is a partition in an operating system process where one or more applications reside.”>应用程序域是2个操作系统进度中一个或多少个应用程序所驻留的分区。 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.”>分歧采纳程序域中的对象的通讯格局有三种:一种是跨应用程序域边界传输对象别本,一种是运用代理调换消息。

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.”>马尔斯halByRefObject对象在地点利用程序域的境界内可直接待上访问。 data-gu=””
data-source=”The first time an application in a remote application domain accesses a <span class="selflink">MarshalByRefObject, a proxy is passed to the remote application.”>远程应用程序域中的应用程序第一遍访问MarshalByRefObject时,会向该远程应用程序传递代理。 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间的对象通讯有二种方法:1种是一连马尔斯halByRefObject
,具备使用代理调换音讯的工夫,别的1种是选用连串化、传递对象别本。

先是种:表现格局上来说,传递的是目标引用。 第3种传递的是目的副本,也正是说不是同三个目标。

也正就此,由于Plugin德姆o.NewDomain.Non马尔斯halByRefObject
即不是马尔斯halByRefObject 的子类,也不能打开体系化,故
不可在多个分裂的AppDomain间通讯。

而地方的不得了,则是由类别化Plugin德姆o.NewDomain.Non马尔斯halByRefObject
对象失败致使的非凡。

假如二个档次 马尔斯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

两个类型为完整的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
目录,此目录下富含了程序集的别本文件。

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

小节:

小节:

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

  假使在另一个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中央银行使CreateInstance中的Type重载创造对象,结果会是Type所属的次序集会被投入到当下AppDomain中,然后Type的实例会在近期AppDomain中开创。

  只有此起彼伏至 马尔斯halByRefObject
的晶莹代理类才可以进行跨域操作。**

  只有继续至 MarshalByRefObject
的晶莹代理类才干够实行跨域操作。**

  所以必要在一连至 马尔斯halByRefObject
的晶莹代理类中张开连锁操作然后再次回到给主应用程序域,只有在代理类中开始展览的代码操作才是属于新建的利用程序域。不然别的运转代理类以外的代码都是属于主应用程序域。

  所以需求在后续至 马尔斯halByRefObject
的透隋朝理类中开始展览有关操作然后回到给主应用程序域,唯有在代理类中进行的代码操作才是属于新建的施用程序域。不然别的运转代理类以外的代码都以属于主应用程序域。

  此章节只是批注了先后集动态加载或卸载热插拔的落成格局,有关AppDomain
和 AppDomainSetup 具体新闻方可参见MSDN上面的文书档案。

  此章节只是讲明了程序集动态加载或卸载热插拔的落到实处方式,有关AppDomain
和 AppDomainSetup 具体新闻可以参照MSDN上面的文书档案。

相关文章

网站地图xml地图