.NET基础:应用程序域AppDomain

简介: 最近再搞.NET中的插件开发,其中涉及到应用程序的热升级,在很多情况下、我们希望用户对应用程序的升级是无感知的,并且尽可能不打断用户操作的。虽然在Web 或者 WebAPI上,由于多点的存在可以逐个停用单点进行系统升级,而不影响整个服务。

最近再搞.NET中的插件开发,其中涉及到应用程序的热升级,在很多情况下、我们希望用户对应用程序的升级是无感知的,并且尽可能不打断用户操作的。

虽然在Web 或者 WebAPI上,由于多点的存在可以逐个停用单点进行系统升级,而不影响整个服务。但是 客户端却不能这样做,毕竟用户一直在使用着。

那么有没有一种方式,可以在用户无感知的情况下(即、不停止进程的情况下)对客户端进行升级呢?

答案是肯定的, 这就是我今天想说的、可以对应用程序进行热升级。当然这种方式也同样适用于 ASP.NET ,这里最核心的就是需要理解:应用程序域AppDomain

不过当前随笔是以 WPF为例子的,并且原理是一样的、代码逻辑也是一样的。

一、应用程序域AppDomain

在介绍插件技术之前、我们需要先了解一些基础性的知识,第一个就是应用程序域AppDomain.

操作系统和运行时环境通常会在应用程序间提供某种形式的隔离。 例如,Windows 使用进程来隔离应用程序。 为确保在一个应用程序中运行的代码不会对其他不相关的应用程序产生不良影响,这种隔离是必需的。这种隔离可以为应用程序域提供安全性、可靠性, 并且为卸载程序集提供了可能。

在 .NET中应用程序域AppDomain是CLR的运行单元,它可以加载应用程序集Assembly、创建对象以及执行程序。

在 CLR 里、AppDomain就是用来实现代码隔离的,每一个AppDomain可以单独创建、运行、卸载。

如果默认AppDomain监听了 UnhandledException 事件,任何线程的任何未处理异常都会引发该事件,无论线程是从哪个AppDomain中开始的。

如果一个线程开始于一个已经监听了 UnhandledException事件的 app domain, 那么该事件将在这个app domain 中引发。

如果这个app domian 不是默认的app domain, 并且 默认 app domain 中也监听了 UnhandledException 事件, 那么 该事件将会在两个app domain 中引发。

CLR启用时,会创建一个默认的AppDomain,程序的入口点(Main方法)就是在这个默认的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.

3、AppDomain vs 应用程序集Assembly

Assembly是.Net程序的基本部署单元,它可以为CLR提供元数据等。

Assembly不能单独执行,它必须被加载到AppDomain中,然后由AppDomain创建程序集中的类型 及 对象。

一个Assembly可以被多个AppDomain加载,一个AppDomain可以加载多个Assembly。

每个AppDomain引用到某个类型的时候需要把相应的assembly在各自的AppDomain中初始化。因此,每个AppDomain会单独保持一个类的静态变量。

4、AppDomain vs 对象object

任何对象只能属于一个AppDomain,AppDomain用来隔离对象。 同一应用程序域中的对象直接通信、不同应用程序域中的对象的通信方式有两种:一种是跨应用程序域边界传输对象副本(通过序列化对对象进行隐式值封送完成),一种是使用代理交换消息。

二、创建 和 卸载AppDomain

前文已经说明了,我们可以在运行时动态的创建和卸载AppDomain, 有这样的理论基础在、我们就可以热升级应用程序了 。

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

创建:

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

创建AppDomain的逻辑非常简单:使用 AppDomain.CreateDomain 静态方法、传递了一个任意字符串 和 AppDomainSetup 对象。

卸载:

AppDomain.Unload(this.domain);

卸载就更简单了一行代码搞定:AppDomain.Unload 静态方法,参数就一个 之前创建的AppDomain对象。

三、在新AppDomain中创建对象

上文已经说了创建AppDomain了,但是创建的新AppDomain却是不包含任何对象的,只是一个空壳子。那么如何在新的AppDomain中创建对象呢?

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

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

并且该方法的重载方法 和 相似功能的重载方法多达十几个。

四、影像复制程序集

创建、卸载AppDomain都有、创建新对象也可以了,但是如果想完成热升级,还有一点小麻烦,那就是一个程序集被加载后会被锁定,这时候是无法对其进行修改的。

所以就需要打开 影像复制程序集 功能,这样在卸载AppDomain后,把需要升级的应用程序集进行升级替换,然后再创建新的AppDomain即可了。

打开影像复制程序集 功能,需要在创建新的AppDomain时做两步简单的设定即可:

AppDomainSetup objSetup = new AppDomainSetup();
 objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
// 打开 影像复制程序集 功能
 objSetup.ShadowCopyFiles = "true";
 // 虽然此方法已经被标记为过时方法, msdn备注也提倡不使用该方法,
 // 但是 以.net 4.0 + win10环境测试,还必须调用该方法 否则,即便卸载了应用程序域 dll 还是未被解除锁定
 AppDomain.CurrentDomain.SetShadowCopyFiles();
 this.domain = AppDomain.CreateDomain("RemoteAppDomain", null, objSetup);
相关文章
|
7天前
|
C# Windows
.NET开源免费的Windows快速文件搜索和应用程序启动器
今天大姚给大家分享一款.NET开源(MIT License)、免费、功能强大的Windows快速文件搜索和应用程序启动器:Flow Launcher。
|
4月前
|
算法 Java 调度
|
7月前
|
Kubernetes 关系型数据库 数据库
.netcore应用容器化部署
.netcore应用容器化部署
|
7月前
|
Kubernetes 数据库 C++
.netcore应用在WSL中的容器化部署
前面,我们讲解了如何在wsl中安装数据库,.netcore运行时,以及如何发布一个.netcore应用,为了构成一个完整的小系列,本节,我们来学习一下,如何将.netcore应用在WSL中容器化。
|
7月前
|
安全 C# 开发工具
模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案
模拟.NET实际应用场景,综合应用三个主要知识点:一是使用dnSpy反编译第三库及调试,二是使用Lib.Harmony库实现第三库拦截、伪造,三是实现同一个库支持多版本同时引用。
模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案
|
前端开发 Ubuntu Linux
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
随着跨平台越来越流行,.net core支持跨平台至今也有好几年的光景了。但是目前基于.net的跨平台,大多数还是在使用B/S架构的跨平台上;至于C/S架构,大部分人可能会选择QT进行开发,或者很早之前还有一款Mono可以支持.NET开发者进行开发跨平台应用。
826 0
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
|
18小时前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
6月前
|
Go
Golang 语言怎么使用 net/http 标准库开发 http 应用?
Golang 语言怎么使用 net/http 标准库开发 http 应用?
26 0
|
7月前
|
关系型数据库 MySQL 容器
.netcore应用容器化时更改Expose端口无法访问
.netcore应用容器化时更改Expose端口无法访问