威尼斯人线上娱乐

【威尼斯人线上娱乐】应用程序热进级,应用程序域落成程序集动态卸载或加载

19 4月 , 2019  

  AppDomain 表示应用程序域,它是3个应用程序在在那之中实施的独门环境。各类应用程序唯有贰个主应用程序域,不过2个应用程序能够创设七个子应用程序域。

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

  AppDomain 表示应用程序域,它是三个应用程序在里面施行的单独环境。每种应用程序只有二个主应用程序域,然而三个应用程序能够成立四个子应用程序域。

  由此能够经过 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接口带有具体操作的得以达成类,正是属于要求动态替换更新的程序集,所以最佳将其编写翻译在3个独自的次第集中,插件目录在布署文件中可计划,示例中放置在E:\Plugins
目录下,示例中代码最后将生成 Kernel.SimpleLibrary.DLL ,最终将编译好的顺序集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运营后将加载此程序集,加载落成运维完成后并释放此程序集。

  以下两句较为首要,最棒设置一下,不设置的结果暂风尚未品味

  //获取或设置提示印象复制是展开依然关闭
  ads.ShadowCopyFiles = “true”;
  //获取或安装目录的名目,那个目录包涵要影像复制的程序集
  ads.ShadowCopyDirectories = ads.ApplicationBase;

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

小节:

  若是在另一个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中动用CreateInstance中的Type重载创设对象,结果会是Type所属的先后集会被到场到近期AppDomain中,然后Type的实例会在眼下AppDomain中开创。

  只有后续至 马尔斯halByRefObject
的透西汉理类技术够举办跨域操作。*【威尼斯人线上娱乐】应用程序热进级,应用程序域落成程序集动态卸载或加载。*

  所以供给在延续至 马尔斯halByRefObject
的透唐朝理类中举行相关操作然后赶回给主应用程序域,只有在代理类中举办的代码操作才是属于新建的行使程序域。不然其余运转代理类以外的代码都以属于主应用程序域。

  此章节只是疏解了先后集动态加载或卸载热插拔的贯彻形式,有关AppDomain
和 AppDomainSetup 具体消息能够参照MSDN上边包车型客车文书档案。

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

  AppDomain 表示应用程序域,它是二个应用程序在个中实行的独自环境。每一个应用程序唯有三个主应用程序域,但是一个应用程序能够创建四个子应用程序域。

后天说一说.NET 中的插件才具,即
应用程序热晋级。在数不清场馆下、我们期待用户对应用程序的进步是无感知的,并且尽量不封堵用户操作的。

  因而能够因此 AppDomain
创建新的选择程序域,在新制造的子应用程序域中加载试行程序集并且在实行落成后刑释程序集财富,来实现系统在运作状态下,程序集的动态加载或卸载,从而到达系统运作中先后集热更新的目的。

  因而能够透过 AppDomain
创建新的选取程序域,在新创造的子应用程序域中加载推行程序集并且在实施完结后获释程序集财富,来促成系统在运转景况下,程序集的动态加载或卸载,从而落成系统运作中等射程序集热更新的目标。

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

  所谓应用程序域,.Net引进的1个概念,指的是1种境界,它标志了代码的运作范围,在中间产生的别的表现,包蕴特别都不会潜移默化到别的应用程序域,起到安全隔开分离的效应。也足以看成是2个轻量级的历程。

  所谓应用程序域,.Net引入的3个概念,指的是一种境界,它标记了代码的运作范围,在在那之中发生的其它表现,包蕴丰裕都不会潜移默化到此外使用程序域,起到平安隔开分离的机能。也足以当做是贰个轻量级的长河。

那正是说有未有一种艺术,能够在用户无感知的场地下(即、不鸣金收兵进程的动静下)对客户端举办升级吗?

二个经过能够涵盖两个使用程序域,各类域之间互相独立。如下是1个.net进度的整合(图片源于互连网)

二个进度能够涵盖多个利用程序域,种种域之间相互独立。如下是1个.net过程的三结合(图片来自网络)

答案是洗颈就戮的,
那便是自个儿先天想说的插件本事、可以对应用程序进行热进级。当然那种方法也如出壹辙适用于
ASP.NET ,

威尼斯人线上娱乐 1

威尼斯人线上娱乐 2

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

以下为总体原理的贯彻代码

以下为全数原理的落到实处代码

一、应用程序域AppDomain

在介绍插件技巧在此以前、大家要求先领悟1些基础性的学识,第四个就是运用程序域AppDomain.

操作系统和平运动转时环境一般会在应用程序间提供某种格局的隔离。例如,Windows
使用进度来隔离应用程序。为有限支撑在一个应用程序中运作的代码不会对此外不相干的应用程序发生不良影响,那种隔开是必需的。那种隔绝可感觉运用程序域提供安全性、可相信性,
并且为卸载程序集提供了说不定。


.NET中利用程序域AppDomain是CL纳瓦拉的周转单元,它能够加载应用程序集Assembly、创立对象以及实践顺序。

在 CL揽胜极光里、AppDomain就是用来完结代码隔断的,各种AppDomain可以独自创设、运转、卸载。

至于AppDomain中的未处理卓殊:

固然私下认可AppDomain监听了UnhandledException
事件,任何线程的别的未处理分外都会引发该事件,无论线程是从哪个AppDomain中开头的。

假使3个线程初步于3个曾经济监察听了UnhandledException事件的 app domain,
那么该事件就要那几个app domain 中引发。

一经那些app domian 不是默许的app domain, 并且 暗中同意 app domain
中也监听了UnhandledException 事件, 那么 该事件将会在多个app domain
中掀起。

CL奥迪Q5启用时,会创造3个暗中同意的AppDomain,程序的入口点便是在这些默许的AppDomain中实行。

AppDomain是足以在运行时进行动态的始建和卸载的,正因如此,才为插件工夫提供了根基(注:应用程序集和系列是无法卸载的,只好卸载整个AppDomain)。

AppDomain和任何概念之间的关联

1、AppDomain vs 进程Process

AppDomain被创设在Process中,二个Process内能够有五个AppDomain。3个AppDomain只可以属于3个Process。

2、AppDomain vs 线程Thread

应该说两者之间未有关联,AppDomain现身的目标是割裂,隔断对象,而 Thread
是 Process中的2个实体、是程序施行流中的矮小单元,保存有眼下命令指针 和
寄存器集合,为线程切换提供恐怕。假若说有关联的话,能够牵强的认为一个Thread能够接纳多少个AppDomain中的对象,四个AppDomain中能够应用八个Thread.

三、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的为主配备单元,它可感到CLLAND提供元数据等。

Assembly不能够独立实践,它必须被加载到AppDomain中,然后由AppDomain创制造进程序集中的项目
及 对象。

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

种种AppDomain引用到某些项目标时候供给把相应的assembly在独家的AppDomain中初叶化。由此,每一种AppDomain会单独保持一个类的静态变量。

4、AppDomain vs 对象object
其余对象只好属于1个AppDomain,AppDomain用来隔开分离对象。
同一应用程序域中的对象间接通讯、分歧选拔程序域中的对象的通讯方式有二种:一种是跨应用程序域边界传输对象别本(通过系列化对目的实行隐式值封送完了),壹种是行使代理交流消息。

主应用程序入口:

主应用程序入口:

二、创建 和 卸载AppDomain

前文已经认证了,大家得以在运转时动态的创办和卸载AppDomain,
有那样的答辩功底在、我们就足以热晋级应用程序了 。

那就让我们来看一下怎么样创设和卸载AppDomain吧

创建:

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

创办AppDomain的逻辑万分简单:使用 AppDomain.CreateDomain
静态方法、传递了叁个任意字符串 和AppDomainSetup 对象。

卸载:

              AppDomain.Unload(this.domain);

卸载就更简便易行了一条龙代码解决:AppDomain.Unload 静态方法,参数就二个以前创制的AppDomain对象。

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

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

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

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

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

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

            Console.ReadLine();
        }
    }
}

叁、在新AppDomain中创设对象

上文已经说了创办AppDomain了,不过成立的新AppDomain却是不分包别的对象的,只是2个空壳子。那么如何在新的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

幸存1接口IPlugin:

威尼斯人线上娱乐 3威尼斯人线上娱乐 4

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

接口 IPlugin

在其它的三个先后集中有其三个得以达成类 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个

威尼斯人线上娱乐 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
GetNonMarshalByRefObject():程序集“Plugin德姆o.NewDomain,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null”中的类型“Plugin德姆o.NewDomain.Non马尔斯halByRefObject”未标志为可体系化。

是由于Plugin德姆o.NewDomain.NonMarshalByRefObject 这么些类别未标志可系列化
而引发的。 那么那种景况下和系列化又有如何关系呢?

请继续往下看。

成立应用程序代理类:

开创应用程序代理类:

6、AppDomain间的对象通讯

前文说过了,AppDomain 是用来隔离对象的,AppDomain
之间的靶子是无法Infiniti制通讯的,那一点在 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">MarshalByRefObject 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">马尔斯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.”>远程应用程序域中的应用程序第1遍访问马尔斯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.”>当跨应用程序域边界使用项目时,类型必须是从MarshalByRefObject承继的,而且由于目的的积极分子在开立它们的行使程序域之外不能够运用,所以不可复制对象的情事。

也便是说AppDomain间的对象通讯有二种办法:一种是再而三马尔斯halByRefObject
,具有使用代理沟通音信的力量,其它一种是运用连串化、传递对象别本。

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

也正由此,由于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

1体化的德姆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接口带有具体操作的兑现类,正是属于须要动态替换更新的程序集,所以最棒将其编写翻译在一个独自的先后集中,插件目录在布置文件中可配置,示例中放置在E:\Plugins
目录下,示例中代码最终将生成 Kernel.SimpleLibrary.DLL ,最终将编写翻译好的次序集放置在 E:\Plugins\Kernel.SimpleLibrary.DLL
路线下,程序运维后将加载此程序集,加载达成运行完结后并释放此程序集。

  以下两句较为重要,最棒设置一下,不设置的后果暂风尚未品味

  以下两句较为主要,最棒设置一下,不安装的结局目前未有尝试

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

  //获取或安装提醒影象复制是张开仍旧关闭
  ads.ShadowCopyFiles = “true”;
  //获取或安装目录的名称,这一个目录包蕴要印象复制的次第集
  ads.ShadowCopyDirectories = ads.ApplicationBase;

  当程序运营起来后,程序集加载之后会在安装的利用程序域缓存目录中复制1份程序集的别本,然后运营别本中的程序集,释放掉本人加载的顺序集。以上示例中会在主程序目录下生成七个Shadow
目录,此目录下富含了先后集的副本文件。

威尼斯人线上娱乐 ,  当程序运转起来后,程序集加载之后会在安装的行使程序域缓存目录中复制一份程序集的副本,然后运营别本中的程序集,释放掉本人加载的顺序集。以上示例中会在主程序目录下生成一个Shadow
目录,此目录下富含了先后集的别本文件。

小节:

小节:

  如果在另四个AppDomain
中加载程序集,然后拿走Type,最终在主AppDomain中利用CreateInstance中的Type重载创立对象,结果会是Type所属的次第集会被出席到方今AppDomain中,然后Type的实例会在时下AppDomain中创立。

  假诺在另2个AppDomain
中加载程序集,然后拿走Type,最后在主AppDomain中运用CreateInstance中的Type重载创立对象,结果会是Type所属的主次集会被出席到当下AppDomain中,然后Type的实例会在现阶段AppDomain中开创。

  只有此起彼伏至 MarshalByRefObject
的透南齐理类才能够进行跨域操作。**

  只有接轨至 马尔斯halByRefObject
的透元朝理类本领够实行跨域操作。**

  所以需求在一连至 马尔斯halByRefObject
的晶莹代理类中举办有关操作然后赶回给主应用程序域,唯有在代理类中张开的代码操作才是属于新建的使用程序域。不然其余运转代理类以外的代码都以属于主应用程序域。

  所以供给在持续至 马尔斯halByRefObject
的晶莹代理类中展开连锁操作然后回来给主应用程序域,唯有在代理类中举办的代码操作才是属于新建的利用程序域。不然其余运维代理类以外的代码都以属于主应用程序域。

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

  此章节只是解说了程序集动态加载或卸载热插拔的完成格局,有关AppDomain
和 AppDomainSetup 具体音讯能够参照MSDN上面包车型大巴文书档案。


相关文章

发表评论

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

网站地图xml地图