托管ASP.NET Web API中如何通过System.IO.File使用相对路径?
错误原因解析
1. 相对路径读取失败原因
本地运行时工作目录为项目根目录,你写的相对路径可以匹配到对应文件,但Azure App Service部署后,应用运行的根目录为C:\home\site\wwwroot,部署后的目录结构和本地项目结构不一致,硬写的相对路径无法匹配到正确位置。
2. 嵌入式资源读取失败原因
GetManifestResourceStream的入参不是文件路径,而是遵循{程序集默认命名空间}.{文件夹层级}.{文件名}规则的资源标识符,你传入路径格式的字符串自然找不到对应资源,返回null导致报错。
解决方案
方案一:直接读取部署目录文件(推荐,可在线修改文件无需重发布)
- 第一步:右键点击项目里的
loyalty-template.html文件,选择「属性」,将复制到输出目录设置为如果较新则复制,确保发布时文件会被同步到Azure部署目录。 - 第二步:使用ASP.NET Core内置的
IWebHostEnvironment获取根目录,动态拼接文件路径,示例代码如下:
private readonly IWebHostEnvironment _webHostEnvironment; // 构造函数注入环境变量 public YourController(IWebHostEnvironment webHostEnvironment) { _webHostEnvironment = webHostEnvironment; } // 业务逻辑中读取文件 public void YourEndpointLogic() { var filePath = Path.Combine(_webHostEnvironment.ContentRootPath, "Assets", "loyalty-template.html"); string body = File.ReadAllText(filePath); }
方案二:嵌入式资源读取
- 第一步:右键点击项目里的
loyalty-template.html文件,选择「属性」,将生成操作设置为嵌入式资源。 - 第二步:获取正确的资源标识符,可在本地调试时先运行如下代码打印所有嵌入资源名,找到对应文件的准确名称:
var allResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // 断点查看allResourceNames数组,匹配到loyalty-template.html对应的资源名
- 第三步:修改读取代码,补充空判断避免报错:
// 替换为你实际拿到的资源名,示例:默认命名空间为TheFoodWorksWebAPI时的写法 var resourceName = "TheFoodWorksWebAPI.Assets.loyalty-template.html"; string body; using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { if (stream == null) { throw new FileNotFoundException("嵌入资源未找到", resourceName); } using var reader = new StreamReader(stream); body = reader.ReadToEnd(); }
方案选型建议
- 如果模板文件需要频繁修改,选择方案一,修改后直接覆盖Azure上的对应文件即可生效,无需重新编译发布。
- 如果模板文件改动少,想要避免部署时漏传文件的问题,选择方案二,文件会被打包到程序集内,不会出现找不到文件的情况。
内容的提问来源于stack exchange,提问作者SeventhWarhawk
相关产品推荐
相关产品推荐

