如何使用ManifestEmbeddedFileProvider读取卫星程序集中的嵌入资源
解决ManifestEmbeddedFileProvider读取卫星程序集嵌入资源的空引用问题
这个问题我之前也碰到过,核心原因确实是带文化标识的资源(比如.de-CH.json)被自动打包到卫星程序集里了——.NET会根据文件名中的文化标记,将这类资源分离到对应文化目录下的[AssemblyName].resources.dll卫星程序集中。而默认的ManifestEmbeddedFileProvider只会扫描主程序集的嵌入资源清单,所以虽然能通过GetFileInfo()找到文件记录(Exists为true),但实际的资源流所在的卫星程序集没被加载,最终调用CreateReadStream()时抛出NullReferenceException。
下面给你两种可行的解决方案:
方法1:加载目标卫星程序集并传入ManifestEmbeddedFileProvider
这种方法适合需要保留多语言资源分离(卫星程序集)的场景,步骤是手动加载对应文化的卫星程序集,再用它初始化ManifestEmbeddedFileProvider:
// 1. 指定目标文化(这里是de-CH) var targetCulture = CultureInfo.GetCultureInfo("de-CH"); // 2. 构建卫星程序集的路径:输出目录/文化名称/主程序集名称.resources.dll var satelliteAssemblyPath = Path.Combine( AppContext.BaseDirectory, targetCulture.Name, $"{assembly.GetName().Name}.resources.dll" ); // 3. 加载卫星程序集 var satelliteAssembly = Assembly.LoadFrom(satelliteAssemblyPath); // 4. 用卫星程序集初始化ManifestEmbeddedFileProvider var manifestProvider = new ManifestEmbeddedFileProvider(satelliteAssembly); // 5. 读取资源(注意这里的文件名要和卫星程序集中的资源名称一致) var fileInfo = manifestProvider.GetFileInfo("your-resource-file.de-CH.json"); if (fileInfo.Exists) { using (var reader = new StreamReader(fileInfo.CreateReadStream())) { var jsonContent = reader.ReadToEnd(); // 处理JSON内容 } }
注意:要确保输出目录下存在对应文化的子文件夹(比如de-CH),且里面包含正确的卫星程序集文件。
方法2:修改csproj配置,阻止资源进入卫星程序集
如果你不需要将资源分离到卫星程序集,可以通过修改项目配置,强制把带文化标识的资源留在主程序集里:
<PropertyGroup> <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> </PropertyGroup> <ItemGroup> <EmbeddedResource Include="**/*.de-CH.json"> <!-- 指定LogicalName,避免自动按文化分离 --> <LogicalName>%(Filename)%(Extension)</LogicalName> <!-- 标记资源为中性文化 --> <Culture>neutral</Culture> </EmbeddedResource> </ItemGroup>
配置完成后重新编译,资源会直接嵌入主程序集,你原来的代码就能正常调用CreateReadStream()读取资源流了,不需要修改C#代码。
方案选择建议
- 如果你需要支持多语言资源切换,且希望按文化分离资源文件,优先选方法1;
- 如果只是简单嵌入特定文化的资源,不需要卫星程序集结构,选方法2更简单直接。
内容的提问来源于stack exchange,提问作者Dejan
相关产品推荐
相关产品推荐

