.Net Core 库中的嵌入式资源

Posted

技术标签:

【中文标题】.Net Core 库中的嵌入式资源【英文标题】:Embedded resource in .Net Core libraries 【发布时间】:2016-12-10 06:48:05 【问题描述】:

我刚刚开始研究 .Net Core,但我没有看到经典资源和任何看起来像资源的东西。例如,在经典的 .Net 类库中,我可以将带有一些脚本的文本过滤器添加到我的项目中,然后我可以将这些文件添加到项目的资源中。之后,我可以通过以下方式轻松使用它:

Connection.Execure(Properties.Resources.MySuperScript);

我看到.Net Core 库中没有这样的功能,至少我没有看到。 .Net Core 中是否有替代方法可以将一些静态数据作为嵌入式资源存储在库中?如果存在,如何使用?

【问题讨论】:

尚不支持资源。也许使用 JSON 或 XML 文件? 我使用了 SQL 脚本的资源,它们包含引号等特殊符号,因此使用 JSON 并不方便,因为应该将这些符号更改为转义序列。以这种形式阅读和修复脚本并不舒适。 :( How do I make an XML file an embedded resource in a vNext (ASP.NET 5) class library?的可能重复 这个答案:***.com/a/57811919/156991 是今天的最佳答案。 【参考方案1】:

更新:

.NET Core 1.1 及更高版本已删除 project.json 并返回到 .csproj 文件。 这改变了第 2 步,但并没有改变那么多。必要的行非常相似:

<ItemGroup>
  <Content Remove="_fonts/OpenSans.ttf" />
  <Content Remove="_fonts/OpenSans-Bold.ttf" />
  <Content Remove="_fonts/OpenSans-Italic.ttf" />
</ItemGroup>
<ItemGroup>
  <EmbeddedResource Include="_fonts/OpenSans.ttf" />
  <EmbeddedResource Include="_fonts/OpenSans-Bold.ttf" />
  <EmbeddedResource Include="_fonts/OpenSans-Italic.ttf" />
</ItemGroup>

可能有类似*.tff的形式;未经证实。

步骤 1 和 3 不变。


要在 .NET Core 1.0 项目中使用嵌入式资源,请执行以下操作:

    照常添加您的嵌入文件。

    示例:名为“_fonts”的目录中的一些 FONT 文件

    修改“project.json”以包含相关资源。

    就我而言:

     "buildOptions": 
        "embed": 
          "include": [
            "_fonts/*.ttf"    
          ]
         
      ,
    

    在代码中访问嵌入的资源。

    var assembly = typeof(MyLibrary.MyClass).GetTypeInfo().Assembly;
    Stream resource = assembly.GetManifestResourceStream("MyLibrary._fonts.OpenSans.ttf");
    

    关键是在GetManifestResourceStream 调用中使用正确的名称。你必须使用[assembly name].[directory].[file name]

【讨论】:

为确保获取正确的资源,请评估目标程序集中的所有可用资源string[] names = assembly.GetManifestResourceNames(); 这对我有用,但最终仍然使用已执行程序集根目录中的文件路径。我有两个 dll,一个用于 API,一个用于 CSV。 API 是运行的库。 CSV 包含我需要阅读的文件。即使文件被列为“Mylibrary.folder.file”,即“CSV.csv.somefile.csv”,它也会尝试读取“solution/API/somefile.csv”。我希望它读取的路径是“solution/CSV/csv/somefile.csv”。关于如何在程序集中保留相对路径的任何建议? 感谢@Luka,您的评论帮助我识别了嵌入资源的实际名称! @Zartag 所说的有意义,除了使用路径无法访问文件这一事实外,主要解决方案是可行的,但在某些用例中,像这样读取流是没有意义的 看起来资源名称的格式使用了程序集的默认命名空间,而不是程序集名称。不过,如上所述,仍然是点分隔的。【参考方案2】:

现在project.json 已被弃用,您必须在.csproj 文件中指定它。

<ItemGroup>
    <EmbeddedResource Include="_fonts\*.ttf" />
</ItemGroup>

您可以使用如图所示的通配符,或者直接列出文件。

【讨论】:

如果没有事后如何获取数据的详细信息,这并没有多大用处。 编译后资源在磁盘的什么位置?我希望在 /bin 文件夹中的某处找到 *.ttf。 @JimAho 文件嵌入在程序集中。 @Brondahl 问题是关于嵌入资源的,这是如何做到的。 :) OP 可能知道从这里去哪里。对于其他寻找如何做到这一点的人,这里有一个与使用 xunit 进行测试相关的示例实现:patriksvensson.se/2017/11/… 来自 Johny 的链接不再有效,这是存档版本:web.archive.org/web/20201024173213/https://patriksvensson.se/…【参考方案3】:

对于较新版本的 .Net Core - 2.0 或更高版本 - 有一个专门的类 EmbeddedFileProvider 可以抽象嵌入式文件读取。要使用它,请将Microsoft.Extensions.FileProviders.Embedded 包添加到您的应用程序中:

dotnet add package Microsoft.Extensions.FileProviders.Embedded

EmbeddedFileProvider 允许您创建流阅读器,并根据您的场景使用:

var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly());
using (var reader = embeddedProvider.GetFileInfo("yourfile.ext").CreateReadStream())

  // some logic with stream reader

【讨论】:

这看起来很有希望,但我遇到了子文件夹中的文件问题。我最终使用 Luka 上面提到的 string[] names = assembly.GetManifestResourceNames(); 关闭了我自己的匹配逻辑。 GetFileInfo() 的文件格式是“Folder.filename.Extension”,没有命名空间。这与使用文件格式“Namespace.Folder.filename.Extension”的 assembly.GetManifestResourceStream() 不同,包括命名空间 我收到一个找不到资源错误。我将文件添加到图像然后将文件类型更改为嵌入。 var resourceName = "X_Signature.jpg";使用 (var stream = assembly.GetFileInfo(resourceName).CreateReadStream()) 我将资源文件设置为嵌入式资源,并设置了自定义的namespace.resources【参考方案4】:

人们已经普遍回答了这个问题,所以这是一个简单的答案。

在使用以下内容之前,应将该文件作为嵌入资源添加到 .csproj / project.json

用法

var myJsonFile = ReadManifestData<Tests>("myJsonFile.json");
    参数:嵌入文件名名称;类型:目标资源程序集中的任何类 查找具有该名称的嵌入式资源 返回字符串值

方法

public static string ReadManifestData<TSource>(string embeddedFileName) where TSource : class

    var assembly = typeof(TSource).GetTypeInfo().Assembly;
    var resourceName = assembly.GetManifestResourceNames().First(s => s.EndsWith(embeddedFileName,StringComparison.CurrentCultureIgnoreCase));

    using (var stream = assembly.GetManifestResourceStream(resourceName))
    
        if (stream == null)
        
            throw new InvalidOperationException("Could not load manifest resource stream.");
        
        using (var reader = new StreamReader(stream))
        
            return reader.ReadToEnd();
        
    

【讨论】:

这是唯一对我有用的。非常感谢!【参考方案5】:

我尚未在文档中确认这一点,但对我来说,检索 Resource.Designer.cs 中的嵌入文件的自动生成的资源代码现在似乎在 .NET Core 3.1 中再次运行。我现在可以通过调用返回 Bitmap 对象的 Properties.Resources.MyImageName 来检索嵌入的 jpg。

【讨论】:

streamreader 只检索字符。如果您的资源文件是基于字符的,则此方法有效 是的,现在可以了,但是您需要添加System.Resources.Extensions 包并在cs/vbproj 中添加&lt;GenerateResourceUsePreserializedResources&gt;true&lt;/GenerateResourceUsePreserializedResources&gt;。但与 .net 框架项目一起使用时可能会导致一些问题。见here

以上是关于.Net Core 库中的嵌入式资源的主要内容,如果未能解决你的问题,请参考以下文章

使用 CMake 将资源(例如,着色器代码;图像)嵌入到可执行文件/库中

.NET Core嵌入式编程开关量GPIO(控制2个灯泡交替闪烁)

将不加载包含文件名的文件名中的嵌入式资源

在类库中嵌入二进制文件

System.ServiceModel 错误在 ASP.NET Core API 中使用嵌入在 Windows 服务中的 WCF 时不支持操作

.NET Core / C# 开发 IOT 嵌入式设备的个人见解