将Configuration项目作为NuGet包引用时触发FileNotFoundException
看起来你遇到的问题是项目拆分到独立仓库并用NuGet引用后,Communication项目无法定位到config.json文件——即使你已经设置了CopyToOutputDirectory,而且NuGet包里也能看到这个文件。这个问题通常和文件复制路径或者读取方式依赖当前工作目录有关,下面给你几个具体的排查和解决方向:
一、检查NuGet包的内容文件配置
当你把Configuration打包成NuGet包时,仅仅设置CopyToOutputDirectory可能不够,因为NuGet需要明确知道要把这个文件作为"内容文件"分发,这样引用它的项目(比如Communication和最终的API项目)才会自动把文件复制到自己的输出目录。
你需要在Configuration项目的.csproj文件里添加以下配置,确保config.json被正确打包:
<ItemGroup> <Content Include="config.json"> <!-- 确保文件复制到项目输出目录 --> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <!-- 标记为NuGet包的内容文件,引用时自动复制 --> <PackageCopyToOutput>true</PackageCopyToOutput> <!-- 指定在NuGet包中的路径,适配不同目标框架 --> <PackagePath>contentFiles\any\any\;content</PackagePath> </Content> </ItemGroup>
添加后重新打包Configuration,更新Communication项目的NuGet引用,然后检查Communication的输出目录是否有config.json,最终再看API项目的输出目录是否也存在这个文件。
二、修改文件读取逻辑,避免依赖当前工作目录
原来项目引用时,Communication的输出目录和API的输出目录可能是关联的,直接用相对路径"config.json"能找到文件。但改成NuGet引用后,API项目的当前工作目录是它自己的输出目录,而如果Communication里的读取代码还是用相对路径,就可能找不到(除非config.json被复制到API的输出目录)。
更可靠的方式是基于程序集位置读取文件,比如在Configuration项目的配置读取代码里改成:
// 获取当前配置类所在的程序集路径 var assembly = typeof(YourConfigServiceClass).Assembly; var assemblyDir = Path.GetDirectoryName(assembly.Location); // 拼接config.json的完整路径 var configPath = Path.Combine(assemblyDir, "config.json"); // 读取文件内容 var configContent = File.ReadAllText(configPath);
这种方式不管是项目引用还是NuGet引用,都能精准定位到程序集所在目录下的config.json,不会受当前工作目录影响。
三、更稳妥的方案:将config.json设为嵌入式资源
如果你不想纠结文件复制的问题,可以直接把config.json嵌入到Configuration的程序集里,这样就不需要依赖外部文件了:
- 在
Configuration的.csproj里修改配置:
<ItemGroup> <EmbeddedResource Include="config.json"> <!-- 设置资源的逻辑名称,方便读取 --> <LogicalName>config.json</LogicalName> </EmbeddedResource> </ItemGroup>
- 修改读取代码:
var assembly = typeof(YourConfigServiceClass).Assembly; // 通过逻辑名称获取嵌入的资源流 using var resourceStream = assembly.GetManifestResourceStream("config.json"); if (resourceStream == null) { throw new FileNotFoundException("无法找到嵌入的config.json资源"); } // 读取资源内容 using var reader = new StreamReader(resourceStream); var configContent = reader.ReadToEnd();
这种方式完全避免了文件复制的问题,资源和程序集绑定在一起,不会出现丢失的情况。
最后验证步骤
- 重新打包
Configuration项目,确保配置生效; - 更新
Communication和API项目的NuGet引用; - 构建API项目,检查输出目录是否有
config.json(如果用第一种方案); - 运行API项目,测试是否还会抛出
FileNotFoundException。
内容的提问来源于stack exchange,提问作者Badri

