.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="Assetslang*"> <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>