隨著 .NET5.0 8 的發布,許多新功能正在被社區成員一一探索;這其中就包含了“單文件發布”這個炫酷的功能,實際上,這也是社區一直以來的呼聲,從 的 msi 開始,我們就希望有這樣一個功能,雖然在 時代,單文件發布的功能顯得“不那么重要”,但正是從這一點可以看出,.NET 的團隊成員一直在致力于實用功能的完善。
在 Java 的世界里,單文件發布一直伴隨著他們的成長,War 文件可以直接上傳到 上運行,話說我們還是有那么一丟丟的羨慕的,不過凡事有利就有弊,單文件發布對于細分模塊的熱更新來說,還有有一點點的不方便。
不過瑕不掩瑜,在微服務概念越來越火熱的今天,相信單文件發布的功能帶給大家更多的是興奮。
什么是單文件發布
首先,我們要清楚的了解,什么是單文件發布。
官方的目標定義:.Net 5.0單個文件解決方案應為:
從上面的目標可以看出,和以往版本最大的不同在于:將所有依賴打包到一個可執行文件中,可直接運行,不影響調試操作。
注意上面的這句話“將所有依賴打包到一個可執行文件中”,而在以往,我們使用 將應用程序進行發布之后,我們會看到,在 下有許多項目依賴的 dll 文件,在 .NET5.0 到來之后,這些依賴文件可收納到一個文件中,瞬間讓人感受到了清涼。
發布操作指令相關命令
可選參數
配置文件設置參數
除了可以使用命令行參數的形式,還可以通過配置文件的形式設置發布參數,編輯項目文件,添加配置節點到文件中并保存即可。
關于 RID 說明見:
這是截止本文發布前的 RID 版本,不排除 .NET5.0 有新的發布
其它參數
除了上面的三個可選參數,我在查詢文檔的過程中還發現,官方還提到了其它參數的使用,目前不確定是否有效
還可以通過設置 e 元素,該設置將指定某些文件不嵌入單個文件之中。
編寫待打包的應用程序
為了更直觀的看出正常發布和單文件發布的區別,我們特別準備了一個 Web 應用程序,并對兩個程序集進行依賴引用。
準備好項目,編譯成功,嘗試發布,打開 控制臺,分別輸入以下命令
linux-x64 和 win-x64 兩個目錄下,分別有 目錄,由于平臺的不同,所引用的依賴也不一樣,這是我們早就了解過的微軟獨立程序包沒反應,我們看看打包前后的區別
以上執行的兩條命令語句,會為我們生成 Linux 和 兩個平臺的程序包,從上圖中可以看出,在打包之前,項目的各種引用依賴都被復制到了發布目錄下,這也是我們之前的程序發布方式,在經過打包后,所有依賴文件都被裝入了一個可執行文件中,在 Linux 平臺下表現為:n , 平臺下則為:n.exe。從打包效果來看,遷移將變得更加方便了。
運行打包程序
打包后的程序和未打包的發布程序在運行方式上沒有太多的差異性,在 平臺上,只需要雙擊 n.exe 就可以運行該打包程序了,本示例創建的是一個 的程序,直接訪問程序偵聽的地址后得到接口返回的結果,如果您創建的是帶有 Razor 視圖或者攜帶其它資源文件的,可能無法訪問指定的 url。
在程序成功運行起來后,我們發現,打包程序并沒有解壓縮文件到磁盤,而是直接從包中加載文件到內存中運行;這是巨大的進步,也是和 War 文件根本的區別。
需要注意的是,該 .exe 文件并不能單獨復制到別的地方運行,你必須把 .exe 當前目錄完整的復制才能運行,這涉及到主機探測的問題,下面我們將會一一提到。
跨平臺的打包文件
通過上面的示例我們了解到微軟獨立程序包沒反應,打包程序總是為不同的平臺生成獨立的包程序,這是為什么呢?這里就涉及到一個概念,也就是 Tool (TIS)
and (ELF)
File (COFF)于1983年引入,最初使用在 AT&T 的 UNIX 系統上。由于 COFF 的各種局限性,比如:節的最大數量受到限制,節名稱,所包含的源文件的長度受到限制,并且符號調試信息無法支持實際的語言。最后,在 V 4 (SVR4) 發布后,AT&T 使用 ELF 替代了 COFF。
工具接口標準委員會 援引委員會規范文件的說明:可執行文件和鏈接格式最初由 UNIX 系統開發和發布實驗室(USL)作為應用程序二進制接口(API)的一部分。工具接口標準委員會 (TIS) 選擇將不斷發展的 ELF 標準作為便攜式對象文件。該標準適用于各種操作系統的 32 位英特爾架構環境的格式。ELF 標準旨在通過向開發人員提供具有一組跨多個操作環境的二進制接口定義。這將減少不同接口實現的數量,從而減少需要重新編寫和編譯的代碼。
ELF 文件結構又分為三種類型,分別是:
(PE)
在 陣營,微軟在此 COFF 標準的基礎上,又進行了創新和發展出了 PE 文件標準
PE 該規范描述了操作系統家族下的可執行文件(圖像)和目標文件的結構。這些文件分別稱為可移植可執行(PE)和公用對象文件格式(COFF)文件。
從上面的兩種規范中可以看出,LinuX 和 都有各自的文件格式規范,而這種規范在一定程度上是不兼容的,不論是從文件結構還是解析方式;所以 .NET5.0 中的打包程序必須為不同的平臺實現獨立的打包器。打包器的實現在 中的 .NET. 庫中。
認識了 ELF 和 PE 文件結構之后,我們就可以對打包器代碼進行閱讀理解。
.NET.
你可以從 上下載 .NET 5.0 的源代碼, 轉到目錄:
/src///.NET.
源碼不太多,可直接進行閱讀,主要理解層次關系即可。
打包器主要包含了三大部分的內容,分別是 、、
在文件 /.cs 的頭部,我們看到了“單文件程序”的文件結構定義
從上面的文件結構中,我們可以非常清晰的看到,單文件程序的結構一共分為三大部分,分別是:
文件頭信息的查看
我們可以通過一些工具去查看已經打包好的文件,在 Linux 下,可以使用 / 等程序來獲取 n 文件的信息。在 下,可以使用 PE Tools 等工具
Linux 下 讀取文件頭信息
從圖中我們可以看到 Type:DYN() 這是一個標準的共享對象文件,關于 ELF 頭部信息的內容不再展開,有興趣的同學可以自行學習相關內容。
下 PE Tools 讀取文件頭信息
已經打包好的程序內部包含了 319(Linux)、(359) 個文件, 版本在未打包前是 84.3MB,打包后是 69.8MB,最重要的是在運行時無需解壓縮,直接從 中運行文件。
文件中的第三部分,也就是 “實體清單( )的寫入代碼在 \.cs\
在成員方法 (cs) 內部迭代調用了 方法,完成了實體清單文件的寫入。
因為解壓器的實現已經轉移到了 和 中,以靜態鏈接庫的方式鏈接到打包器中,且該部分代碼由 C++ 進行編寫,鑒于 C++ 水平有限,在這里不作介紹。
結束語
編寫這篇文章耗費了我大量的時間,期間大量閱讀海量的參考資料、文獻、標準文檔、制作文章配圖等等,寫干貨文章真的需要投入巨大的精力和時間,希望你們喜歡。
文章進行到這里,我知道肯定還有很多同學沒看過癮,但是我們可以通過回顧打包器的開發進度表來體驗一下 .NET 團隊的開發熱情。
主要參考資料
.NET團隊計劃經理 的博客:
進度表:
-file:
ELF文檔:
ELF維基百科:
:
PE文檔:
PE Tools: