NET插件本事,应用程序域完成程序集动态卸载或加载

  AppDomain 表示应用程序域,它是贰个应用程序在中间进行的独门环境。每一种应用程序只有3个主应用程序域,但是三个应用程序能够制造多少个子应用程序域。

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

  AppDomain 表示应用程序域,它是叁个应用程序在里边进行的单身环境。各类应用程序只有一个主应用程序域,不过1个应用程序能够创立多个子应用程序域。

  由此得以由此 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中创建。

  只有后续至 MarshalByRefObject
的透明清理类才可以进行跨域操作。**

  所以供给在一连至 MarshalByRefObject
的透北周理类中举行相关操作然后归来给主应用程序域,唯有在代理类中开始展览的代码操作才是属于新建的行使程序域。不然别的运营代理类以外的代码都是属于主应用程序域。

  此章节只是解说了程序集动态加载或卸载热插拔的完成方式,有关AppDomain
和 AppDomainSetup 具体音信方可参照MSDN上边的文书档案。

通过 AppDomain
应用程序域落实程序集动态卸载或加载,
AppDomain表示应用程序域,它是二个应用程序在里头执行的独自环境。每一个应用程序…

  AppDomain 表示应用程序域,它是四个应用程序在中间举行的独门环境。每一种应用程序只有二个主应用程序域,可是2个应用程序能够创造三个子应用程序域。

明天说一说.NET 中的插件本事,即
应用程序热晋级。在多数情形下、大家期待用户对应用程序的进级是无感知的,并且尽量不封堵用户操作的。

  由此能够透过 AppDomain
创制新的行使程序域,在新创设的子应用程序域中加载实践程序集并且在实行达成后释放程序集财富,来兑现系统在运转情形下,程序集的动态加载或卸载,从而达到系统运作中先后集热更新的指标。

  因而可以通过 AppDomain
创建新的使用程序域,在新创造的子应用程序域中加载推行程序集并且在实施实现后刑释程序集能源,来兑现系统在运作状态下,程序集的动态加载或卸载,从而达到系统运维中先后集热更新的指标。

虽说在Web 或许WebAPI上,由于多点的存在能够每个停用单点进行系统升级,而不影响整个服务。可是客户端却不能够如此做,毕竟用户直接在行使着。

  所谓应用程序域,.Net引进的一个定义,指的是1种境界,它标志了代码的周转范围,在里头发生的此外表现,包罗尤其都不会潜移默化到其它应用程序域,起到安全隔开的法力。也能够用作是1个轻量级的进程。

  所谓应用程序域,.Net引进的1个概念,指的是1种境界,它标志了代码的运作范围,在内部发生的其他表现,包括充裕都不会潜移默化到任何使用程序域,起到安全隔开的坚守。也足以当作是三个轻量级的过程。

那正是说有未有一种办法,能够在用户无感知的处境下(即、不鸣金收兵进度的意况下)对客户端实行提高吗?

一个历程可以包括多少个使用程序域,种种域之间相互独立。如下是四个.net进程的叁结合(图片来源于互连网)

多少个过程能够包蕴多少个使用程序域,各样域之间相互独立。如下是1个.net经过的结缘(图片源于网络)

答案是任其自然的,
那便是小编明日想说的插件本领、可以对应用程序进行热进级。当然那种方式也1如既往适用于
ASP.NET ,

亚洲必赢官网 1

亚洲必赢官网 2

NET插件本事,应用程序域完成程序集动态卸载或加载。只是当下小说是以 WPF为例子的,并且原理是千篇一律的、代码逻辑也是如出壹辙的。

以下为全部原理的完结代码

以下为全体原理的落实代码

壹、应用程序域AppDomain

在介绍插件技术在此以前、大家供给先精晓部分基础性的知识,第多少个就是使用程序域AppDomain.

操作系统和平运动作时环境1般会在应用程序间提供某种方式的割裂。例如,Windows
使用进度来隔开应用程序。为有限帮助在3个应用程序中运作的代码不会对任何不相干的应用程序产生不良影响,那种隔开分离是供给的。那种隔绝可感到利用程序域提供安全性、可相信性,
并且为卸载程序集提供了恐怕。


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

在 CL揽胜里、AppDomain就是用来兑当代码隔断的,每三个AppDomain能够独自创设、运营、卸载。

至于AppDomain中的未处理至极:

假如暗中同意AppDomain监听了UnhandledException
事件,任何线程的其余未处理非常都会抓住该事件,无论线程是从哪个AppDomain中初露的。

若果叁个线程起先于一个1度监听了UnhandledException事件的 app domain,
那么该事件就要这几个app domain 中引发。

设若这几个app domian 不是暗中认可的app domain, 并且 暗中认可 app domain
中也监听了UnhandledException 事件, 那么 该事件将会在四个app domain
中抓住。

CL凯雷德启用时,会创设3个暗许的AppDomain,程序的入口点正是在那么些默许的AppDomain中实施。

AppDomain是能够在运转时开始展览动态的创办和卸载的,正因如此,才为插件能力提供了根基(注:应用程序集和类型是不能够卸载的,只可以卸载整个AppDomain)。

AppDomain和其余概念之间的涉及

1、AppDomain vs 进程Process

AppDomain被成立在Process中,二个Process内得以有四个AppDomain。叁个AppDomain只好属于一个Process。

2、AppDomain vs 线程Thread

应当说两者之间未有涉及,AppDomain出现的指标是与世隔膜,隔开分离对象,而 Thread
是 Process中的二个实体、是程序试行流中的微乎其单反元,保存有眼下下令指针 和
寄存器集合,为线程切换提供大概。借使说有提到的话,能够牵强的感到三个Thread可以动用四个AppDomain中的对象,三个AppDomain中得以采用八个Thread.

三、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的中坚配备单元,它可以为CL智跑提供元数据等。

Assembly不能够独立执行,它必须被加载到AppDomain中,然后由AppDomain成立程序集中的种类及 对象。

三个Assembly能够被八个AppDomain加载,3个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的逻辑非凡轻便:使用 AppDomain.CreateDomain
静态方法、传递了1个任意字符串 和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.

并且该格局的重载方法 和 相似功效的重载方法多达十多个。

开立异的行使程序域并且在新的选取程序域中调用透北宋理类:

成立新的利用程序域并且在新的利用程序域中调用透明清理类:

4、影象复制造进程序集

创立、卸载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:

亚洲必赢官网 3亚洲必赢官网 4

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

接口 IPlugin

在别的的2个程序集中有其多个兑现类 Plugin:

亚洲必赢官网 5亚洲必赢官网 6

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

实现类 Plugin

在此外的3个程序集中还有3个

亚洲必赢官网 7亚洲必赢官网 8

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

空类型 NonMarshalByRefObject

测试程序如下:

亚洲必赢官网 9亚洲必赢官网 10

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

测试程序

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

创建AppDomain成功

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

是由于Plugin德姆o.NewDomain.Non马尔斯halByRefObject 这么些项目未标识可系列化
而引发的。 那么那种意况下和系列化又有何样关联吧?

请继续往下看。

开创应用程序代理类:

成立应用程序代理类:

陆、AppDomain间的对象通讯

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

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

data-source=”<span class="selflink">马尔斯halByRefObject is the base class for objects that communicate across application domain boundaries by exchanging messages using a proxy.”>马尔斯halByRefObject是经过动用代理沟通音信来跨应用程序域边界举行通讯的靶子的基类。 data-gu=””
data-source=”Objects that do not inherit from <span class="selflink">马尔斯halByRefObject are implicitly marshal by value.”>不是从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.”>马尔斯halByRefObject对象在地头利用程序域的界线内可一贯访问。 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间的靶子通讯有二种方法:1种是继续马尔斯halByRefObject
,具有使用代理交流消息的力量,其余1种是选取种类化、传递对象别本。

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

也正由此,由于Plugin德姆o.NewDomain.Non马尔斯halByRefObject
即不是马尔斯halByRefObject 的子类,也不得以开始展览系列化,故
不可在三个例外的AppDomain间通讯。

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

若果多个类别 马尔斯halByRefObject的子类 并且 SerializableAttribute,
则该类型的对象不可能被此外AppDomain中的对象所走访,
当然那种地方下的该品种对象中的成员也不容许被访问到了

反之,则足以被此外AppDomain中的对象所访问

比方三个项目 马尔斯halByRefObject的子类, 则跨AppDomain所得到的是
(为了好理解说成靶子引用,实质为代理)

只要一个品类 SerializableAttribute, 则跨AppDomain所获得的是
,该别本是由此类别化进行值封送的

这时传递到其它AppDomain 中的对象 和 当前指标已经不是同多少个对象了

假定多个品类 马尔斯halByRefObject的子类 并且 塞里alizableAttribute,
则 马尔斯halByRefObject 的先期级更高

此外:.net 基本项目 、string 类型、 List<T>
等品类,尽管尚未标识SerializableAttribute,
可是他们依然得以系列化。也等于说那个项目都得以在区别的AppDomain之间通讯,只是传递的都是指标别本。

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

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

        public TransparentAgent() { }

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

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

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

        public TransparentAgent() { }

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

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

七、完整的Demo

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

PluginDemo

PluginDemo.NewDomain

三个体系为全体的德姆o

负有涉嫌到必要动态加载或释放的财富,都急需放在代理类中开展操作,唯有在此代理类中展开托管的代码才是属于新建的应用程序域的操作。

具有关乎到须要动态加载或释放的能源,都急需放在代理类中实行操作,只有在此代理类中实行托管的代码才是属于新建的使用程序域的操作。

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

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

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

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

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

读取配置文件音讯:

读取配置文件音讯:

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

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

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

配备文件有关布置音信:

布局文件有关配置音信:

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

创设接口消息:

始建接口音信:

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

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

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

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

        string Put(string plus);
    }
}

创造接口自定义属性:

创立接口自定义属性:

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

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

        public string Describtion { get; set; }

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

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

        public string Describtion { get; set; }

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

成立承袭至IObjcet接口带有具体操作的落到实处类:

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

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

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

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

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

        public PlugPut() { }


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

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

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

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

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

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

        public PlugPut() { }


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

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

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

  承继至IObjcet接口带有具体操作的贯彻类,正是属于须求动态替换更新的程序集,所以最佳将其编写翻译在二个独立的程序集中,插件目录在配置文件中可配置,示例中放置在E:\Plugins
目录下,示例中代码末了将生成 Kernel.SimpleLibrary.DLL ,最终将编写翻译好的程序集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运营后将加载此程序集,加载完成运营完成后并释放此程序集。

  承袭至IObjcet接口带有具体操作的落实类,就是属于须求动态替换更新的程序集,所以最棒将其编译在1个独门的次第集中,插件目录在布署文件中可配备,示例中放置在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
目录,此目录下富含了先后集的别本文件。

小节:

小节:

  假如在另一个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地图