明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

使用.NET框架簡(jiǎn)化公布與處理DLL Hell問題(1)

[摘要]簡(jiǎn)介 Microsoft® .NET 框架介紹了幾個(gè)新功能,旨在簡(jiǎn)化應(yīng)用程序發(fā)布和解決 DLL Hell。最終用戶和開發(fā)人員都熟悉版本和發(fā)布問題,這些問題會(huì)伴隨著如今基于組件的系統(tǒng)一同出現(xiàn)。例如,每個(gè)最終用戶都在他們的機(jī)器上安裝了一個(gè)新的應(yīng)用程序,沒料到已有應(yīng)用程序神秘地停止了工作...
簡(jiǎn)介

Microsoft® .NET 框架介紹了幾個(gè)新功能,旨在簡(jiǎn)化應(yīng)用程序發(fā)布和解決 DLL Hell。最終用戶和開發(fā)人員都熟悉版本和發(fā)布問題,這些問題會(huì)伴隨著如今基于組件的系統(tǒng)一同出現(xiàn)。例如,每個(gè)最終用戶都在他們的機(jī)器上安裝了一個(gè)新的應(yīng)用程序,沒料到已有應(yīng)用程序神秘地停止了工作。多數(shù)開發(fā)人員花費(fèi)時(shí)間使用 Regedit,努力保持所有必要的注冊(cè)項(xiàng)一致以便激活 COM 類。

.NET 框架中用于解決 DLL Hell 問題的設(shè)計(jì)原則和實(shí)現(xiàn)技術(shù)是建立在 Microsoft Windows® 2000 的基礎(chǔ)上的, Rick Anderson 所著的 The End of DLL Hell(英文)和 David D'Souza, BJ Whalen 及 Peter Wilson 所著的 Implementing Side-by-Side Component Sharing in Applications (Expanded) (英文)中都有說明。.NET 框架提供的許多功能都在這兩篇文章中有所描述,包括應(yīng)用程序隔離和并行組件,用于建立在 .NET 平臺(tái)的應(yīng)用程序。您將了解 .NET 平臺(tái)上提供的版本支持,它能使本地 Windows 應(yīng)用程序更緊密地匯集。

本文介紹了匯編的概念,并描述 .NET 如何使用匯編來解決版本和發(fā)布問題。我們將特別討論匯編如何構(gòu)建,如何命名以及編譯器和通用語(yǔ)言運(yùn)行時(shí)如何使用匯編來記錄和加強(qiáng)應(yīng)用程序片段間的版本依賴。我們也將討論應(yīng)用程序和管理員如何能通過我們所稱的版本策略定制版本行為。

介紹并說明了匯編后,將展示幾個(gè)發(fā)布方案,以便使您對(duì) .NET 框架中提供的各種打包和分發(fā)選項(xiàng)多少有一些了解。


問題敘述

版本

從客戶的角度,最常見的版本問題就是我們所說的 DLL Hell 問題。簡(jiǎn)單地講, DLL Hell 是指當(dāng)多個(gè)應(yīng)用程序試圖共享一個(gè)公用組件(如某個(gè)動(dòng)態(tài)連接庫(kù)(DLL)或某個(gè)組件對(duì)象模型(COM)類)時(shí)所引發(fā)的一系列問題。最典型的情況是,某個(gè)應(yīng)用程序?qū)⒁惭b一個(gè)新版本的共享組件,而該組件與機(jī)器上的現(xiàn)有版本不向后兼容。雖然剛安裝的應(yīng)用程序運(yùn)行正常,但原來依賴前一版本共享組件的應(yīng)用程序也許已無法再工作。在某些情況下,問題的起因更加難以預(yù)料。比如,當(dāng)用戶瀏覽某些 Web 站點(diǎn)時(shí)會(huì)同時(shí)下載某個(gè) Microsoft ActiveX® 控件。如果下載該控件,它將替換機(jī)器上原有的任何版本的控件。如果機(jī)器上的某個(gè)應(yīng)用程序恰好使用該控件,則很可能也會(huì)停止工作。

在許多情況下,用戶需要很長(zhǎng)時(shí)間才會(huì)發(fā)現(xiàn)應(yīng)用程序已停止工作。結(jié)果往往很難記起是何時(shí)的機(jī)器變化影響到了該應(yīng)用程序。用戶可能會(huì)回憶起一周前安裝了一些東西,但安裝與目前看到的狀態(tài)并沒有任何明顯的關(guān)聯(lián)。 更糟的是,現(xiàn)在很少有診斷工具幫助用戶(或幫助他們的技術(shù)支持人員)確定有什么問題。

這些問題的原因是應(yīng)用程序不同組件的版本信息沒有由系統(tǒng)記錄或加強(qiáng)。而且,系統(tǒng)為某個(gè)應(yīng)用程序所做的改變會(huì)影響機(jī)器上的所有應(yīng)用程序—現(xiàn)在建立完全從變化中隔離出來的應(yīng)用程序并不容易。

很難建立一個(gè)隔離應(yīng)用程序的一個(gè)原因是當(dāng)前運(yùn)行時(shí)環(huán)境只允許單獨(dú)版本組件或應(yīng)用程序的安裝。這個(gè)限制意味著組件的編寫者必須以向后兼容的方式編寫他們的代碼,否則當(dāng)他們安裝新組件的時(shí)候會(huì)有終止已有應(yīng)用程序的風(fēng)險(xiǎn)。實(shí)際上,如果可能的話,編寫永遠(yuǎn)向后兼容的代碼是非常難的。在 .NET 中,side by side 概念是版本問題的核心。"Side by side" 是在同一臺(tái)機(jī)器上同時(shí)運(yùn)行不同版本的相同組件的能力。使用支持并列的組件,編程人員不必努力維護(hù)嚴(yán)格的向后兼容,因?yàn)椴煌膽?yīng)用程序自由使用某個(gè)共享組件的不同版本。

發(fā)布和安裝

現(xiàn)在安裝應(yīng)用程序是多步過程。一般,安裝一個(gè)應(yīng)用程序包括復(fù)制許多軟件組件到磁盤,和在系統(tǒng)中進(jìn)行一系列描述那些組件的注冊(cè)項(xiàng)。

注冊(cè)表中的項(xiàng)和磁盤上文件的分隔使復(fù)制應(yīng)用程序和卸載他們非常困難。而且,在注冊(cè)表中完全描述某個(gè) COM 類所需的許多項(xiàng)之間關(guān)系非常松散。這些項(xiàng)常常包括聯(lián)合類、接口、類型庫(kù)和 DCOM app ID 的項(xiàng),不涉及任何放在注冊(cè)表文檔擴(kuò)展或組件類別的項(xiàng)。要時(shí)常手工保持這些項(xiàng)的同步。

最后,需要該注冊(cè)足跡激活任何 COM 類。這極大地復(fù)雜了發(fā)布分布式應(yīng)用程序的過程,因?yàn)楸仨毜矫總(gè)客戶端的機(jī)器進(jìn)行適當(dāng)?shù)淖?cè)項(xiàng)。

如今另一個(gè)共同問題是:對(duì)一個(gè)正在運(yùn)行的應(yīng)用程序進(jìn)行更新是不現(xiàn)實(shí)的。這是 Web 應(yīng)用程序最大的問題,Web 應(yīng)用程序必須停止工作然后重啟動(dòng)以更新應(yīng)用程序使用的 COM 類。

這些問題主要由從組件自己分離傳來的組件描述引起的。換句話說,應(yīng)用程序不是自描述的和獨(dú)立的。


解決方案的特性

.NET 框架必須提供以下基本的能力解決剛剛描述的問題:

應(yīng)用程序必須是自描述的:自描述的應(yīng)用程序去掉了對(duì)注冊(cè)表的依賴,能夠毫無影響的安裝和簡(jiǎn)單的卸載和復(fù)制。


必須記錄和加強(qiáng)版本信息:版本支持必須建立在平臺(tái)內(nèi)部以保證依賴的適當(dāng)版本在運(yùn)行時(shí)載入。


必須記得“上次已知的正確配置”:當(dāng)應(yīng)用程序成功運(yùn)行時(shí),平臺(tái)必須提供記住這套一起工作的組件的能力—包括它們的版本—。


必須支持并列組件:允許多個(gè)版本的組件同時(shí)安裝和運(yùn)行在機(jī)器上,允許調(diào)用者指定他們需要載入的版本代替不知不覺被強(qiáng)迫的版本。.NET 框架通過允許框架自己的多個(gè)版本同時(shí)存在于一臺(tái)單獨(dú)的機(jī)器上使并列鄰先了一步。這極大地簡(jiǎn)化了升級(jí)問題,因?yàn)楣芾韱T如果需要可以選擇運(yùn)行不同版本 .NET 框架上的不同應(yīng)用程序。


必須使應(yīng)用程序隔離: .NET 框架必須簡(jiǎn)化(實(shí)際上已經(jīng)默認(rèn))編寫不受機(jī)器上其他應(yīng)用程序的改變影響的應(yīng)用程序。


匯編:積木

匯編是 .NET 框架用于解決剛描述的版本和發(fā)布問題的積木。匯編是類型和資源的發(fā)布單元。在許多方面匯編和現(xiàn)在的 DLL 相同。從本質(zhì)上講,匯編是“邏輯 DLL”。

匯編是通過元數(shù)據(jù)調(diào)用清單自描述的。就像 .NET 使用元數(shù)據(jù)描述類型一樣,它也使用元數(shù)據(jù)描述包含類型的匯編。

匯編不僅僅于發(fā)布有關(guān)。例如,.NET 中的版本在匯編層完成 —沒有任何減少,就像一個(gè)模塊或類型的版本化。而且,匯編還用于在應(yīng)用程序之間共享代碼。包含某個(gè)類型的匯編是該類型標(biāo)志的一部分。

訪問安全系統(tǒng)的代碼在其許可模型的內(nèi)核中使用匯編。匯編的編寫者在清單中記錄一組運(yùn)行該代碼所需求的許可,然后管理員將許可授權(quán)給基于匯編的代碼,此匯編包含該代碼。

最后,匯編也是類型系統(tǒng)和運(yùn)行時(shí)間系統(tǒng)的核心,在其中他們?yōu)轭愋秃头⻊?wù)建立了一個(gè)可視的邊界作為解決引用類型的運(yùn)行時(shí)間范圍。

匯編清單

清單明確包括以下有關(guān)匯編數(shù)據(jù):

標(biāo)識(shí):一個(gè)匯編標(biāo)識(shí)由三部分組成:名稱、版本號(hào)和選項(xiàng)文化。


文件列表:清單包括所有組成匯編的文件列表。對(duì)于每個(gè)文件,在建立清單時(shí)記錄它的名稱和內(nèi)容的加密信息。該信息在運(yùn)行時(shí)驗(yàn)證以確保發(fā)布單元的一致。


引用的匯編:匯編間的關(guān)系保存在收集的匯編清單中。從屬信息包括版本號(hào),它用于運(yùn)行時(shí)保證載入正確版本的關(guān)系。


輸出類型和資源:對(duì)類型和資源可用的可視選項(xiàng)包括“僅在我的匯編中可視”和“對(duì)我的匯編之外的調(diào)用者可視!


許可需求:匯編許可需求分為三組:匯編運(yùn)行需求、需要的但匯編還有一些即使沒授權(quán)的功能的需求,以及編寫者不想?yún)R編被授權(quán)的需求。
IL 反匯編 (Ildasm) SDK 工具對(duì)于在匯編中查看代碼和元數(shù)據(jù)很有幫助。圖 1 是一個(gè)以 Ildasm 現(xiàn)實(shí)的范例清單。.assembly 表示匯編而 .assembly extern 包含有關(guān)其他匯編所依賴的信息。


<img src=/article/UploadPic/200671953759787.gif>

圖 1. 以 IL 反匯編顯示的范例清單

匯編結(jié)構(gòu)

到此為止,匯編主要以邏輯概念描述。本節(jié)通過描述他們?nèi)绾卧谖锢砩象w現(xiàn)幫助您使匯編更加具體。

通常,匯編由四個(gè)元素組成:匯編元數(shù)據(jù)(清單)、元數(shù)據(jù)描述類型、實(shí)現(xiàn)該類型的媒介語(yǔ)言 (IL) 代碼和一組資源。不是所有的這些都出現(xiàn)在每個(gè)匯編中。只有清單是嚴(yán)格需要的,但類型或資源需要給匯編一些重要的功能。

有幾個(gè)關(guān)于這四個(gè)元素能如何包裝的選項(xiàng)。例如,圖 2 表示包含整個(gè)匯編:清單、類型元數(shù)據(jù)、IL 代碼和資源。

圖 2. 包含所有匯編元素的 DLL

另一種情況,一個(gè)匯編的內(nèi)容也許分割為多個(gè)文件。在圖 3 中,作者選擇將一些有用的代碼分離到一個(gè)不同的 DLL 中,并在它的原始文件中保留一個(gè)大的資源文件(這里是一個(gè) JPEG 文件)。這樣做的一個(gè)原因就是優(yōu)化代碼的下載。.NET 框架只在引用時(shí)才下載文件,所以如果匯編包含經(jīng)常被訪問的代碼或資源,那么將他們分成單獨(dú)的文件將提高下載的效率。

圖 3. 匯編元素分割為多個(gè)文件