单文件发布时content文件被忽略,需改用none标记或嵌入资源:前者在.csproj中设并用assembly.getexecutingassembly().location拼路径;后者设build action为embeddedresource,用getmanifestresourcestream按“根命名空间+点号分隔路径”读取。

单文件发布不是“打个包就完事”,默认情况下 dotnet publish -p:PublishSingleFile=true 只打包 IL 和运行时,你的 config.json、images/、templates/ 都不会进去——运行时直接报 FileNotFoundException 或读出来是空内容。
为什么单文件发布后找不到配置文件或资源
因为 Content 类型的文件(如 appsettings.json、logo.png)在 PublishSingleFile=true 下被完全忽略。MSBuild 默认只把编译产出(dll/exe)和运行时塞进单文件,其他文件一律留在发布目录外。
-
Content项不参与单文件打包,即使设置了CopyToOutputDirectory - 若项目里用了
<none update="config\*.json" copytopublishdirectory="PreserveNewest"></none>,但 Build Action 是Content,依然无效——必须是None - 路径硬编码如
"./config/appsettings.json"在单文件下指向的是当前工作目录,不是 exe 所在目录,大概率错
如何让 JSON/图片等文件打进单文件并正确读取
两种可靠方式,选其一即可,别混用:
- 显式标记为发布资产:在
.csproj中加<none update="config\**" copytopublishdirectory="PreserveNewest"></none>,然后代码中用Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)拼路径(注意:不是AppContext.BaseDirectory,它在单文件下返回临时解压路径) - 嵌入为资源(推荐小体积、不变动的文件):设 Build Action 为
EmbeddedResource,在.csproj中确保没加CopyToPublishDirectory;读取时用Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApp.config.appsettings.json"),资源名 = 根命名空间 + 文件相对路径(点号分隔),可用GetManifestResourceNames()调试确认
启用 PublishTrimmed 或 IncludeNativeLibrariesForSelfExtract 后资源更易丢
这两个开关本身不删你的资源,但会改变运行时行为:
-
PublishTrimmed=true不影响None文件打包,但若你同时开了IncludeNativeLibrariesForSelfExtract=true(.NET 6+ 默认开启),原生库(如 SQLite、SkiaSharp)会被解压到临时目录——而你的None资源仍只在单文件内,不会自动同步过去 - 如果你在代码里用
Directory.GetCurrentDirectory()或AppDomain.CurrentDomain.BaseDirectory去找资源,会跑到那个临时目录下,必然找不到 - 结论:只要用了单文件,所有路径逻辑必须基于
Assembly.GetExecutingAssembly().Location构造,且资源必须明确标记为None+CopyToPublishDirectory或走嵌入资源
最容易被忽略的一点:嵌入资源的命名空间拼写必须严格匹配项目默认命名空间和文件路径,大小写、斜杠转点号、是否带扩展名,一个字符错就 null;建议第一次用时先打印 GetManifestResourceNames() 全列表看一眼。











