不安裝執行時執行.NET程式

2022-08-03 15:00:58

好久沒寫文章了,有些同學問我公眾號是不是廢了?其實並沒有。其實想寫的東西很多很多,主要是最近公司比較忙,以及一些其他個人原因沒有時間來更新文章。這幾天抽空寫了一點點東西,證明公眾號還活著。
長久以來的認知,對於受控程式碼 .NET / JAVA ,都是需要在伺服器上安裝 SDK 或者執行時的。比如 .NET Framework 4.XX ,JDK/JRE.XX 等。其實從 .NET Core 2.1 開始我們的 .NET 程式可以獨立打包成可以執行檔案,在伺服器上根本不需要安裝任何執行時相關的東西就可以執行。這個釋出模式在某些情況下可以大大提高部署的效率。以下簡單介紹一下。

「獨立」部署模式

在釋出介面部署模式選擇「獨立」,點選儲存之後然後正常釋出。等到釋出完成之後,檢視 publish 目錄,可以發現裡面生成了一大堆檔案,數量有上百個。這裡其實就包含了 runtime 相關的檔案。

我們把這堆檔案全部複製到某個未安裝過 .NET SDK 或者 runtime 的 windows 伺服器上,找到 SelfContainedTest.exe 檔案,雙擊執行。如果一切順利,會啟動一個控制檯。


存取一下伺服器的 5000 口,看到測試資料被成功的輸出了,證明我們的 .NET 程式可以正常執行了 。

單檔案

上面的操作我們已經可以不安裝執行時在伺服器上執行 .NET 程式了。但是那麼多檔案看著不太優雅,下面讓我們的 .NET 程式打包成一個檔案。
開啟發佈設定介面,勾上「生成單個檔案」

點選儲存,釋出之後,在 publish 目錄可以看到只剩下 6 個檔案了。排除組態檔,pdb 檔案等,其實真正的程式只是 SelfContainedTest.exe 檔案,所以稱之為單檔案。雙擊這個檔案我們的程式就可以正常的執行了。

裁剪

以上我們已經把程式從多個檔案打包成一個檔案了。這個檔案我們可以看到有 70 M ,對於我們一個簡單的演示程式來說 70M 也挺大了。那麼有什麼辦法來縮小我們的可以執行檔案嗎?
其實我們只要在釋出設定上開啟裁剪功能,就可以縮小我們的程式。

在釋出設定介面勾上「裁剪未使用的程式碼」,點選儲存,釋出之後,在 publish 資料夾下面生成的 SelfContainedTest.exe 檔案縮小到了 30M 左右。

裁剪的注意點

這裡大概說一下裁剪的原理。當我們使用裁剪功能的時候,釋出程式會開始分析我們的程式碼,哪些類被使用,哪些類沒有使用,沒有使用的類就會被刪除掉,使用這樣的原理來減小發布後程式集的大小。
但是以上方法顯然會有一個問題,那就是無法識別動態性很強的程式碼,比如反射實現的某些功能。比如以下程式碼:

string s = Console.ReadLine();
Type type = Type.GetType(s);
foreach (var m in type.GetMethods())
{
    Console.WriteLine(m.Name);
}

顯然以上程式碼靜態分析沒辦法知道程式最終需要使用那些類,因為目標類是通過 Console.ReadLine 方法輸入進去的。在程式沒有執行的時候誰也不知道哪些類會被使用。

在 IIS 上執行

上面我們演示程式執行的時候是寄宿在控制檯上的,這樣的話很容易被人誤關閉。其實單檔案發布的程式照樣可以使用 IIS 來託管。
按照正常的 IIS 釋出網站的流程設定之後,把應用程式池設定為 「無受控程式碼」 存取對應的埠程式就可以正常執行了。

在 linux 上執行

以上我們都是在 windows 上測試,現在讓我們試一下在 linux 上執行它。
在 linux 上執行的話,需要在釋出設定介面修改「目標執行時」為 linux-64 。

釋出成功後把生成的檔案複製到 linux 伺服器上。cd 到目錄,執行以下程式碼。

chmod +x SelfContainedTest
./SelfContainedTest

很不幸,我們的程式沒有按計劃執行起來。

通過搜尋後發現,需要設定一個環境變數。修改執行的程式碼:

export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
./SelfContainedTest

執行完之後我們的程式應該會順利的啟動。存取一下對應的 http 介面,可以看到正確的輸出了。

總結

通過以上演示,我們根本沒必要在伺服器(windows/linux)上安裝任何 SDK 或者執行時就可以完整的執行我們的 .NET 程式。而且通過裁剪之後我們的程式的大小也縮小到了一個很小的範圍。以上功能對於網際網路行業來說可能沒什麼必要,畢竟大家走的都是容器化部署,伺服器上本來就不需要安裝執行時。但是對於一些傳統行業,比如醫院這樣的環境,還有很多需要在伺服器上人肉部署的場景。在這些場景之下就非常有意義了,可以大大的體高部署的效率。畢竟不是誰都可以很快的在伺服器上安裝好執行時,特別是 linux 伺服器。
其實不安裝執行時來執行程式還有一個辦法,那就是使用 AOT 釋出,這個我們下次再講。

關注我的公眾號一起玩轉技術