在C#项目中,将文本、图片或配置文件作为嵌入资源编译进程序集,可以有效避免部署时文件丢失的问题。EmbeddedFileProvider是Microsoft.Extensions.FileProviders命名空间下提供的专用类型,它把程序集里的内嵌资源包装成统一的IFileProvider接口,使我们可以用一致的方式读取内容。

一、嵌入资源与程序集命名规则
在Visual Studio中,把一个文件设为“嵌入的资源”生成操作,编译器会将其写入程序集清单。资源名并不是原始文件名,而是由项目的默认命名空间、文件夹路径和文件名共同拼接而成。例如默认命名空间为MyApp,文件位于Resources目录下名为config.json,那么最终资源名通常是MyApp.Resources.config.json。
这种命名方式经常让初学者在调用GetManifestResourceStream时传入错误名称而返回null。我们可以通过反射列出所有资源名来排查。理解这一规则是使用EmbeddedFileProvider的前提,因为provider内部也是依据这些名称来定位资源的。
using System;
using System.Reflection;
var asm = Assembly.GetExecutingAssembly();
foreach (var name in asm.GetManifestResourceNames())
{
Console.WriteLine(name);
}
二、EmbeddedFileProvider基本用法
EmbeddedFileProvider的构造函数接收Assembly,并可指定基础命名空间。创建后,通过GetFileInfo方法传入相对于基础命名空间的资源路径,即可获得IFileInfo对象。IFileInfo的Exists属性指示资源是否存在,OpenReadStream方法返回只读流,这与物理文件提供程序的行为完全一致。
下面示例展示如何读取内嵌的config.json。假设基础命名空间已设为MyApp,资源放在Resources文件夹,则路径写为Resources/config.json。注意路径使用正斜杠,provider会自动映射到对应的清单资源名。
using Microsoft.Extensions.FileProviders;
using System;
using System.IO;
using System.Reflection;
var assembly = Assembly.GetExecutingAssembly();
// 指定基础命名空间,后续路径可省略该前缀
var provider = new EmbeddedFileProvider(assembly, "MyApp");
IFileInfo file = provider.GetFileInfo("Resources/config.json");
if (file.Exists)
{
using var stream = file.OpenReadStream();
using var reader = new StreamReader(stream);
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
else
{
Console.WriteLine("未找到嵌入资源");
}
三、遍历与目录检索
除了单个文件,EmbeddedFileProvider也支持GetDirectoryContents方法。它返回一个IDirectoryContents,包含该“目录”下的所有资源条目。由于嵌入资源本质是扁平的清单名称,provider会根据基础命名空间和路径前缀模拟出目录结构,方便与需要目录枚举的组件集成。
以下代码列出Resources目录下的所有内嵌资源。若某个子项IsDirectory为false,即可作为文件读取。这种能力在构建可插拔模块、提供多语言资源包时非常实用,无需关心物理路径。
using Microsoft.Extensions.FileProviders;
using System;
using System.Reflection;
var provider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly(), "MyApp");
var dir = provider.GetDirectoryContents("Resources");
foreach (var item in dir)
{
Console.WriteLine($"名称: {item.Name}, 是否目录: {item.IsDirectory}");
}
四、在依赖注入与框架中的集成
ASP.NET Core等框架大量使用IFileProvider。我们可以把EmbeddedFileProvider注册到服务容器,或合并到CompositeFileProvider中,同时支持物理文件和嵌入资源。例如在静态文件中间件或Razor视图定位器中,嵌入资源能作为备用来源,提升发布包的自包含性。
下面演示如何用ServiceCollection添加嵌入文件提供程序,并在开发中组合多个来源。这种方式让业务代码只依赖IFileProvider抽象,不感知资源究竟来自磁盘还是程序集,降低了部署复杂度。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using System.Reflection;
var services = new ServiceCollection();
var embedded = new EmbeddedFileProvider(Assembly.GetExecutingAssembly(), "MyApp");
services.AddSingleton<IFileProvider>(embedded);
var provider = services.BuildServiceProvider().GetRequiredService<IFileProvider>();
var info = provider.GetFileInfo("Resources/config.json");
Console.WriteLine(info.Exists);
五、常见误区与排查建议
最常见的错误是资源名不匹配。若GetFileInfo总是返回Exists为false,应先打印GetManifestResourceNames确认实际名称。另一个误区是混淆默认命名空间与程序集名称,基础命名空间参数应为代码中的默认命名空间,而非Assembly.GetName().Name。
此外,嵌入资源在编译后无法修改,适合只读场景。若需要运行时改写,应改用物理文件或外部配置中心。理解这些边界,才能在高内聚发布与灵活配置之间做出合理选择。
EmbeddedFileProvider嵌入资源Assembly修改时间:2026-08-05 22:45:30