首頁>技術>

最近再搞.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);

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 程式設計師利器-有網工具(NetTools)