Silverlight™ 2 包含對 Windows® Presentation Foundation (WPF) UI 框架所做的大量 更改:新控件、豐富的網絡 API 和數字版權管理 (DRM) 支持。Silverlight 2 中的一項主要更改就是能 夠使用與 Microsoft® .NET 兼容的語言編寫 Web 客戶端。在本文中,我將重點介紹 Silverlight 的開發核心:CoreCLR。
在過去的十幾年中,我們已經擁有了許多不同的 Web 編程技術,從 CSS 到 ECMAScript 變體。其中 大部分技術都特定於 Web 編程任務,舉例來說,通過編程 CSS 所學到的技術並不適用於其他領域。相比 之下,Silverlight 2 允許您使用適用於桌面編程的相同 .NET Framework 技術(如基類庫、XAML 和 C# ),還允許您將這些技術直接應用到 Web 客戶端應用程序。此外,也無需創建單獨的 CoreCLR 開發環境 :您可以直接使用 Visual Studio® 來設計、開發、調試和配置 C# 或 Visual Basic®,就像使 用桌面應用程序一樣。我們創建的 Silverlight 2 CoreCLR 可使 Web 編程像桌面編程一樣豐富。
雖然擁有一個豐富的編程環境對開發人員很有好處,但用戶並不想下載大型的浏覽器插件。為了 使 Silverlight 適合用戶使用,必須實現快速安裝。我們已將 Beta 1 的安裝大小縮減到 4.3MB,通過 寬帶連接大約需要 6 到 10 秒鐘即可安裝。想想 .NET Framework 2.0 CLR 的兩個主要核心部件 (mscorwks.dll 和 mscorlib.dll)的大小大約都等於 Silverlight 2 coreclr.dll 和 mscorlib.dll 相加的大小,這真是很了不起的成就。
深入了解 CoreCLR 引擎
自 2005 年 10 月發行 CLR 的 2.0 版本後即開始了 CoreCLR 的設計。它的兩個主要設計目標是大小和兼容性:從編程人員的角 度來看,針對 CLR 的編碼應該始終相同,而從用戶的角度來看,下載必須非常小。由於 Silverlight 旨 在提供一組不同於桌面 CLR 的方案,因此,我們可以進行一些更改,以簡化 CoreCLR 並允許我們縮減 Silverlight 的安裝大小。但是,堆棧底部的一致性至關重要。行為差異(即使這些行為差異都正確)表 明堆棧上部有錯誤。
為了確保兼容性,我們在堆棧底部的各個組件中使用相同的代碼。執行引擎 和虛擬機都是相同的。其中包括類型系統和元數據、垃圾回收器 (GC)、JIT 編譯器、線程池以及運行時 引擎的其他核心部件。
但是,為了適應 Web 應用程序方案,進行了一些更改。例如,富 Internet 應用程序通常簡單且運行時間短,JIT 編譯器主要側重於減少啟動時間,而非執行更復雜的優 化操作。同樣,服務器垃圾回收模式可以對使用相似分配模式的多個工作線程進行優化,而對 Web 托管 應用程序則行不通。因此,Silverlight 只包含針對交互式應用程序進行優化的標准工作站 GC。但是, 在 Silverlight 應用程序中使用 Microsoft 中間語言 (MSIL) 和元數據的方式與在針對桌面的托管應用 程序中的使用方式完全相同,而且應用程序的行為在用戶的桌面上和在浏覽器上一致。
事實上, Silverlight 並不打算取代桌面 CLR,這就引發了核心引擎中最大的變化:CoreCLR 將與桌面 CLR 進程 並行運行。過去,我們從來就不能在同一進程中運行 CLR 的兩個版本。這是一個難題,原因有好幾個, 其中一個是管理進程范圍的狀態:每個 CLR 實例都假定進程中只有一個 CLR,因而只有它可以處理其靜 態數據。如果 CLR 1.1 和 2.0 中都包含 staticFoo 變量,而且在同一個進程中同時加載了這兩個 CLR 版本,則任一版本都無法在不影響另一個 CLR 狀態的情況下寫入 staticFoo 變量。
雖然進程范 圍的狀態是最明顯的問題,但在一個進程中並行運行兩個 CLR 還會導致其他問題。例如,如果您同時運 行了兩個 GC,如何防止其中一個 GC 掛起另一個 GC 的線程?此外,空間占用也存在問題:如果在一個 進程中加載多個 CLR,每個 CLR 都必須加載代碼(這些代碼可能都相同),並為其靜態變量和托管堆留 出相應的空間。
在某些重要的情況下,托管 CoreCLR 需要與桌面運行時並行運行。如果 CoreCLR 和桌面 CLR 不能同時運行,我們將無法編寫托管 Web 浏覽器控件(該控件可以導航到使用 Silverlight 的網頁)的桌面 Windows 窗體或 WPF 應用程序。若要解決這個潛在問題,只需在您的 Windows 計算機 上安裝依賴於 CLR 的 Silverlight:每次安裝 Windows XP SP2 和 Windows Vista® 時,都會隨操 作系統安裝相當新的 CLR。但是,無論您的計算機上安裝了哪種版本的 CLR(對於 Mac OS X 來說,即使 您的計算機上未安裝任何 CLR),只要使所有 Silverlight 代碼在 CoreCLR 上運行都必須確保絕對兼容 。因此,我們努力使 CoreCLR 可以與桌面 CLR 進程並行運行,我們相信經過我們的努力用戶會獲得更好 的 Silverlight 體驗。
CoreCLR 安全模型
核心引擎中的另一個重大更改與新的安全模型有關。注意,一直以來,.NET 開發人員使用代碼訪問安全性 (CAS) 來阻止不受信任的代碼執行特權操作。CAS 功能非常強大,但使用 起來相當復雜。它允許用戶或管理員使用權限集定義各種代碼沙箱,然後將各個程序集映射到這些沙箱中 。對於 Silverlight 應用程序,我們只需一個沙箱,該沙箱等效於 Internet Explorer® 用來在網 頁中運行腳本的沙箱。使用此簡化方案,我們可以刪除所有的 CAS 策略。
我們也簡化了安全執行 模型。新的模型基於在 CLR 2.0 版本中引入的一個概念 — 安全透明。透明模型的本質是將代碼分 為以下三類:透明代碼、SafeCritical 代碼或關鍵代碼。透明代碼的信任級別最低,它無法提升權限或 訪問計算機上的敏感資源或信息。在 Silverlight 2 中,所有的應用程序代碼都是透明代碼。關鍵代碼 的信任級別最高,它可以通過 P/Invoke 與系統進行交互,甚至可以包含無法驗證的代碼。對於 Silverlight 2,所有關鍵代碼必須是 Silverlight 平台的一部分。SafeCritical 代碼則相當於二者之 間的橋梁,借助它,透明代碼可以通過調用關鍵代碼來訪問系統資源。我們可以將關鍵代碼想象成 Windows 的內核 API;將透明代碼想象成用戶應用程序代碼;而將 SafeCritical 代碼想象成用戶代碼和 內核代碼之間的 API。
透明代碼只能調用其他透明代碼或 SafeCritical 代碼,而 SafeCritical 代碼可以代表用戶代碼調用關鍵代碼。SafeCritical 代碼需要將輸入規范化或調整為標准格式,淨化關 鍵代碼的輸出以保護系統的安全性(參見圖 1)。
圖 1 CoreCLR 中的安 全執行機制
將輸入規范化為關鍵代碼的情況要比淨化輸出的情況更簡明易懂。例如,如果我的 Web 應用程序需要在本地磁盤上寫入一個文件,則使用獨立存儲即可實現此操作。但是,如果您不希望此 應用程序寫入名為“..\..\..\..\bootmgr”的文件中,就必須確保輸入的格式正常、規范。認為關鍵代 碼的輸出存在安全風險的情況非常罕見。主要的安全概念是,控制信息洩露在減小受到攻擊者各種類型的 攻擊方面起著至關重要的作用。假如我嘗試訪問系統上的一些用戶信息,獲得的響應是“權限被拒絕”。 但作為另一個用戶重復相同的訪問操作時,我獲得的響應是“用戶 Bob 不存在”。如果我知道會獲得這 兩種響應,重復嘗試無效訪問就可以獲得系統上的用戶名列表。
簡化的安全策略為使用 .NET 代碼的開發人員帶來了極大的便利,同時也有助於開發人員研究 .NET 代碼。我們已盡可能少地使用關鍵代碼和 SafeCritical 代碼了。如果使用的大部分都是透明代碼,將有 助於減少需要我們進行深入安全檢查的代碼的數量。雖然仍要檢查透明代碼的正確性和安全性,但至少我 們清楚這些代碼不會執行任何特權操作。許多 Silverlight 大型部件(包括動態語言運行時 (DLR))都 是全部使用透明代碼編寫的。通過限制 Silverlight 的特權部件,我們可以將精力集中到確實需要仔細 檢查的領域,從而提高所交付的產品的安全性。
基類庫
.NET Framework 在桌面上的演變 發展是為了解決用戶和服務器這兩方面的問題。因此,基類庫 (BCL) 中的很多功能在 Web 客戶端上沒有 任何意義。例如,由於 Silverlight 不支持 CAS,因此大部分 System.Security 都不是必要的。諸如 System.Console 等許多其他類在 Web 中也沒有任何意義(既然如此,為什麼還要包含精簡的 System.Console 類呢?因為它可以幫助我們測試產品)。
我們使用庫與使用核心引擎的目標是一 樣的:將功能集減至最少,以便 .NET 開發人員無需全面了解全新技術即可成功使用。.NET Compact Framework 解決了不同情況中出現的同一問題,我們從中獲得了一些靈感和指導。雖然我們從 Silverlight 中刪除了 BCL,但保留了 .NET Compact Framework 和 Silverlight 間的兼容性。通過此 方法在所有平台之間共享一個庫,可以在最大程度上重復使用 .NET 技術。
您可以在 BCL 中的許 多地方找到重復的功能。有些功能在 BCL 內部就是重復的,例如,泛型集合與非泛型集合。有時,有些 功能已經存在於基操作系統中,如全球化支持。我們不僅不必支持 Silverlight BCL 中的所有替代選項 ,還可以通過省略此重復行為來提供最佳的性能和一致性。
由於 .Net Framework 2.0 版本中引入了對泛型集合的支持,所以我們主張人們將注意力轉移到泛型 上。在運行時的 1.x 版本中,通用數據結構必須基於對象,相同的核心數據結構類才能用來創建不同類 型的集合。使用泛型類型參數,編譯器可以通過擴展這些通用數據結構來提供類型安全性,從而使代碼更 易於編寫和維護。此外,相對於非泛型集合來說,泛型集合對值類型執行操作效果更好,因為它不需要框 起項目。總之,泛型不但可以提供非泛型集合提供的所有功能,而且由於不必使用重復,所以 Silverlight BCL 中可以不包含諸如 ArrayList 等非泛型集合。
每個人或多或少都了解一些全球化問題:許多歐洲地區將逗號用作小數點;中文數字將每四位數分為 一組 (1000,0000),等等。.NET Framework 在內部實施全球化功能,因此它可以在多個領域正常運行。 為此,它包含所有支持區域的全球化數據,使以 .NET 為目標的應用程序在所有支持的 Windows 版本中 行為一致。但是,這也存在一些弊端。CLR 必須包含大型數據表,而這些數據通常會隨著時間的流逝而失 效。此外,這些數據都以 Windows 為中心,因此某些 .NET 區域中的數據與 Mac OS X 中相同區域不同 。鑒於這些原因,CoreCLR 不包含自己的全球化數據。相反,System.Globalization.CultureInfo 可以 使用宿主操作系統提供的全球化功能。因此,Silverlight 應用程序在 Mac OS X 中運行時,其行為更像 Mac,而在 Windows 中運行時,其行為更像 Windows 應用程序。
總之,我們已經盡力在 CLR、.NET Compact Framework 和 Silverlight 之間維護類似的 API 外圍應 用,但在 BCL 中仍分散著其他細微差異。例如,由於 Silverlight 中有一個單獨的 UI 線程,因此它還 包含一個單獨的 Dispatcher 對象以承載 UI 的工作項隊列。借助 Dispatcher,您可以通過非 UI 線程 更新 UI。此代碼允許您使用在其他線程(如後台線程)中創建的集合更新 UI 元素 — MyListBox:
MyListBox.Dispatcher.BeginInvoke(() => MyListBox.ItemsSource = MyItems);
我們建議在 Silverlight 中使用 System.ComponentModel.BackgroundWorker,因為它可以在完成時 封裝更新的 UI,但出於兼容性考慮,我們仍將低級別線程 API 包括在內,如
System.Threading.ThreadPool.QueueUserWorkItem 和 System.Threading.Monitor.Enter。
跟安全透明模型一樣,Silverlight BCL 中的部分新增功能實際上在先前版本的 .NET Framework 中 就出現過。獨立存儲就是其中一個很好的示例,它可為經過沙箱處理的應用程序提供虛擬化文件系統。自 .NET Framework 1.0 推出以來,獨立存儲就已存在,但它僅適用於幾種有限的情況。Silverlight 側重 於經過沙箱處理的應用程序,因此它可以完全利用獨立存儲:
using (IsolatedStorageFile isoStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamWriter writer = new StreamWriter(isoStore))
{
writer.Write("This is an isolated storage file.");
}
}
與 Web 浏覽器中的 Cookie 一樣,獨立存儲允許 Silverlight 應用程序跨調用維持其狀態。但是, 獨立存儲提供的完全虛擬化文件系統支持目錄和文件的創建。雖然獨立存儲不是為了存儲高價值的數據( 如密碼),但是其存儲位置不明確,而且僅限於擁有存儲的應用程序進行訪問。
獨立存儲的配額由應用程序組定義,以 Silverlight 應用程序的域名為基礎。例如,如果兩個 Microsoft 應用程序位於 microsoft.com 的目錄下,則它們將共享一個應用程序組,也就表示這兩個應 用程序共享相同配額。默認情況下,為每個應用程序組提供 1MB 的存儲區。
但是,如果某個應用程序需要更多存儲空間,它可以通過一個可指定的對話框來提示用戶以請求更大 配額,例如,microsoft.com 需要將其配額增加到 8MB。那麼,用戶可以啟用或禁用獨立存儲,還可以在 Silverlight 配置對話框中刪除當前使用的獨立存儲(在對話框中稱為應用程序存儲)。應用程序組還可 以有共享存儲區,這就使相關應用程序可以共享其中的數據。
雖然獨立存儲已經出現一段時間,但只有在 Silverlight 中使用後才引起人們的關注。適用於交互式 Web 應用程序的可配置安全文件系統,不僅可以開發文字處理程序等傳統的 Office 應用程序,也可以開 發維護大量數據的應用程序,如股票跟蹤系統。
跨平台運行
Silverlight 可以在非 Windows 平台上運行。我們與 Novell 有合作,在 Mono 項目的 Moonlight 運行時的整個過程中都支持 Linux。Microsoft 還致力於研究適用於業界領先的 Symbian OS 和 Windows Mobile 的 Silverlight 版本。Moonlight 可以在 Mono 上運行,而 Silverlight 的移動版本可以在 .NET Compact Framework(其內存占用量比 CoreCLR 低)上運行。但是,Silverlight 的 Mac OS X 版 本只能在與 Windows 完全相同的 CoreCLR 上運行。
我們只有在平台適配層 (PAL) 的幫助下,才能達到此目標。此 PAL 是專為在不同平台上運行而編寫 的 API。它可為錯誤處理、文件處理、網絡服務、線程語義等提供抽象層。PAL 中的功能可以共享 Win32 API 的名稱,但實現過程卻不同。某些 API 只可以通過 PAL 功能的參數傳遞到 OS X 功能中,而其他 API 需要使用自定義邏輯才能使 OS X 功能與 Windows API 簽名相匹配。CoreCLR 使用的若干 Windows 功能 Mac 中並不具備,因此必須完全在 PAL 中實現(參見圖 2)。
圖 2 平台適配層
許多 Silverlight PAL 得益於開發 Shared Source Common Language Infrastructure (SSCLI)(也 稱為 Rotor)所獲得的教訓。SSCLI 可以在許多 UNIX 類型的平台和 Windows 上運行。基操作系統功能 因各個 UNIX 類型平台差異很大。SSCLI PAL 必須同時在微內核(如 Mac OS X 中的 Mach 內核)和單內 核上才能運行,並且需要處理線程、異常處理和網絡堆棧等不同的操作系統服務。由於 Silverlight 僅 適用於 Windows 和 Intel Mac 計算機,因此,我們能夠為 PAL 中的許多功能編寫特定的 Mac 實現,這 對 PAL 的大小和性能很有幫助。
PAL 僅支持運行 Silverlight 必須使用的 Win32 子集,而無需支持注冊表、GDI+ 或 COM。我們不能 在 OS X 之上實現 Windows,也不能實現足夠的 Windows 功能來支持桌面 CLR 的所有功能。將 PAL 限 制為僅支持 Silverlight 可以縮小其大小並加快執行速度。
當您意識到 OS X 與 Windows 之間的差異有多大時,就會了解隱藏操作系統之間的差異是多麼棘手的 問題。大部分 OS X 使用 Objective C 編寫,而其提供的異常處理系統與 C++ 不兼容。CLR 創建的 I/O 線程與工作線程不同。這些 I/O 線程基於 Windows NT 3.5 中引入的 I/O 完成端口,而 OS X 中不存在 此類端口。由於 Windows 中存在反斜槓目錄分隔符,因此即使像查找文件這樣簡單的操作在 Mac 上也不 一樣。
在 CoreCLR 的整個設計和開發過程中,我們側重於使提供的環境能讓開發人員重用現有技術和工具, 以便為安全的小型運行庫開發更為豐富的內容。大部分決策的驅動力都源自富 Internet 應用程序的精減 方案,但部分設計還得益於過去的工作成果。對 CoreCLR 所做的部分決策將最終在桌面上得到體現。例 如,您可以期待桌面 CLR 的下一個版本能夠與 CLR 的其他版本並行運行。另外,對改進的安全透明模型 所做的大部分更改也會出現在下一版本的 CLR 中。
我們仔細考慮了哪些操作對基於 Web 的方案有意義,哪些在運行庫中並無必要。我們希望自己做出了 正確的選擇,而且相信您會對我們應如何繼續改進提出建議。來體會對 Silverlight 2 進行編寫代碼的 樂趣吧!請密切關注此內容以便將來繼續深入探索 CoreCLR。
請將您想詢問的問題和提出的意見發送至 [email protected]。