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

好久沒寫文章了,有些同學問我公眾號是不是廢了?其實並沒有。其實想寫的東西很多很多,主要是最近公司比較忙,以及一些其他個人原因沒有時間來更新文章。這幾天抽空寫了一點點東西,證明公眾號還活著。
長久以來的認知,對於託管程式碼 .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 發布,這個我們下次再講。

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

Tags: