.NetCore可以將發布時產生的所有零碎文件直接打包成一個單獨的運行文件相信大家都已經知道了,但在發布過程還有一些小技巧,我們今天就來聊一聊。
1. 入門
我們可以通過命令行將項目發布為單個文件:
dotnet publish -c Release -r win10-x64 -o release/win10-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true
也可以通過在項目配置文件中的參數來實現:
<PropertyGroup> <PublishSingleFile>true</PublishSingleFile> <PublishTrimmed>true</PublishTrimmed> </PropertyGroup>
- 命令行參數說明
參數 | 說明 | 備注 |
---|---|---|
--no-self-contained | 不包含runtime | 用戶需自己安裝runtime |
-r | 目標平台 | win-x64, osx-x64, linux-x64 RID參考 |
-c | 發布類型 | Debug, Release |
-o | 程序發布目錄 | - |
PublishSingleFile | 發布為單個文件 | true, false |
PublishTrimmed | 去除未引用對象 | true false |
PublishTrimmed參數可以有效減少發布文件的體積
--no-self-contained可減少約30M的程序體積,但不能與PublishTrimmed參數同時使用
2. 進階
單文件非常輕松的就發布出來了,但還沒過30秒,一般都會發出類似這樣的嚎叫:"我去,怎么啟動失敗?文件加載不了?"
大多數情況是因為非程序文件沒有被一起發布,別急,我們繼續聊....
2.1 修改元數據
我們可以顯式的排除一些文件被打包,通過為項目配置文件添加參數
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
例如,要將某些文件放在發布目錄中,但不將它們捆綁到單文件中:
<ItemGroup> <Content Update="*.xml"> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <ExcludeFromSingleFile>true</ExcludeFromSingleFile> </Content> </ItemGroup>
或者像這樣復制整個目錄
<ItemGroup> <None Update="Assets\lang\*"> <Link>lang\%(Filename)%(Extension)</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <ExcludeFromSingleFile>true</ExcludeFromSingleFile> </None> </ItemGroup>
2.2 修改代碼
但僅這樣是不夠的,因為單文件是在沙箱中運行,所以需要在修改一下代碼讓它從程序所在目錄調用文件,比如這樣
#if DEBUG //debug模式調用路徑 string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json"); #else //release調用路徑 string filePath = Path.Combine(Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName), "config.json"); #endif LoadFile(filePath)
這樣就能取到原來的文件了,不過既然都說到這了,我們就順便說說.NetCore調用目錄函數之間的區別
2.3 目錄區別
//模塊啟動位置(非單文件模式時主程序調用為dotnet所在位置) Console.WriteLine("StartDir:" + Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName)); //程序啟動位置(單文件模式時是虛擬容器內位置) Console.WriteLine("AppBaseDir:" + AppContext.BaseDirectory); Console.WriteLine("AppBaseDir:" + AppDomain.CurrentDomain.SetupInformation.ApplicationBase); Console.WriteLine("AppBaseDir:" + AppDomain.CurrentDomain.BaseDirectory); //程序當前目錄,單文件模式時是用戶目錄,VSCode運行時為項目目錄(不推薦使用) Console.WriteLine("CurrentDirectory:" + Environment.CurrentDirectory); //同上 Console.WriteLine(Directory.GetCurrentDirectory()); //程序所在的硬盤根目錄 Console.WriteLine("RootDir:" + Directory.GetDirectoryRoot( Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory) )); //用戶目錄(~/) Console.WriteLine("UserProfile:"+Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); //桌面目錄(~/Desktop) Console.WriteLine("DesktopDirectory:"+Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)); //系統目錄(/System) Console.WriteLine("SystemDirectory:"+Environment.SystemDirectory); //程序數據目錄(~/.config) Console.WriteLine("ApplicationData:"+Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
2.4 符號文件(可選)
默認情況下,符號文件不會嵌入到單文件中,而是作為單獨的文件保留在發布目錄中(如 .pdb
.ni.pdb
app
.guid.map
),設置以下屬性可將符號文件包含在單文件中。
<PropertyGroup>
<IncludeSymbolsInSingleFile>true</IncludeSymbolsInSingleFile>
</PropertyGroup>