96

I just have started looking into .Net Core, and I don't see classical resources and anything what looks like resources. In classical .Net class libraries I was able to add, for example, text filtes with some script to my project, than I can add these files to project's resources. After that I could easily use that by the following way:

Connection.Execure(Properties.Resources.MySuperScript);

I see that there isn't such feature in .Net Core libraries, at least I don't see. Is there an alternative in .Net Core to store some statical data as an embedded resource in libraries? And how to use that if it exists?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Don Tomato
  • 3,311
  • 3
  • 30
  • 48
  • 2
    Resources are not yet supported. Maybe using a JSON or XML file? – Gerardo Grignoli Aug 04 '16 at 09:05
  • I used resources for SQL-scripts, they contain special symbols like quotes, so using JSON isn't convenient because these symbols should be changed for escape sequences. It isn't comfortable to read and fix scripts in such form. :( – Don Tomato Aug 04 '16 at 13:08
  • Possible duplicate of [How do I make an XML file an embedded resource in a vNext (ASP.NET 5) class library?](http://stackoverflow.com/questions/34482073/how-do-i-make-an-xml-file-an-embedded-resource-in-a-vnext-asp-net-5-class-libr) – Michael Freidgeim Feb 03 '17 at 12:24
  • This answer: https://stackoverflow.com/a/57811919/156991 is the best for today. – Mike Eshva Dec 05 '19 at 19:29

6 Answers6

125

UPDATE:

.NET Core 1.1 and later have dropped project.json and returned to .csproj files. This changes Step 2, but not all that much. The necessary lines are very similar:

<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>

There may be a similar *.tff form; unconfirmed.

Steps 1 and 3 are unchanged.


To use embedded resources in .NET Core 1.0 project do the following:

  1. Add your embedded file(s) as usual.

    Example: some FONT files on a directory named "_fonts"

    enter image description here

  2. Modify "project.json" to include the related resources.

    In my case:

     "buildOptions": {
        "embed": {
          "include": [
            "_fonts/*.ttf"    
          ]
        } 
      },
    
  3. Access the embedded resource in code.

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

    The key point is to use the right name on GetManifestResourceStream call. You have to use [assembly name].[directory].[file name].

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Nacho Coll
  • 1,290
  • 1
  • 10
  • 3
  • 43
    to be sure you are fetching the right resource, evaluate all the resources available in your target assembly `string[] names = assembly.GetManifestResourceNames();` – Luka Mar 01 '17 at 09:37
  • 1
    This works for me, but it still ends up using a file path which is in the root of the executed assembly. I have two dlls, one for API and one for CSV. API is the library which is run. CSV contains the files I need to read. Even if the files are listed out as "Mylibrary.folder.file", which is "CSV.csv.somefile.csv" it will attempt to read "solution/API/somefile.csv". The path I would expect it to read would be "solution/CSV/csv/somefile.csv". Any suggestions for how to preserve the relative path within the assembly? – melwil Mar 08 '17 at 11:13
  • Thank you @Luka your comment helped me identify the actual names of the embedded resources! – Allen Rufolo May 25 '17 at 17:08
  • what @Zartag says make sense except for the fact that files are not reachable by using path, the main solution works yes, but there are some use cases where make no sense read the stream just like that – Jose Luis Berrocal Aug 14 '17 at 19:12
  • 3
    Looks like the format of the resource name uses the *default namespace* of the assembly, instead of the assembly name. Still dot-delimited as stated above, though. – tiwahu Jan 26 '18 at 21:09
  • you could use _fonts\**\*.ttf. Or even **\*.ttf. This will pull in folders as well, either starting in _fonts or root. – Jimmie Clark Sep 01 '20 at 13:39
  • to make this work, I had to remove ".GetTypeInfo()": `var assembly = typeof(MyLibrary.MyClass).Assembly;` – Robert H. Mar 18 '22 at 15:46
  • Can someone explain the 'MyLibrary.MyClass' type, and it should be in our case or at least how it works? – Pavlos Mavris Feb 15 '23 at 09:45
56

Now that project.json is deprecated, you have to specify this in the .csproj file.

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

You can use a wildcard as shown, or just list out the files explicitly.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • 12
    This isn't much use without the details of how to get the data out afterwards. – Brondahl Oct 16 '18 at 15:59
  • Where are the resources located on disk after compilation? I'd expect to find *.ttf somewhere inside the /bin folder. – Jim Aho Dec 14 '18 at 12:37
  • 6
    @JimAho the files are embedded in the assembly. – Drew Noakes Dec 14 '18 at 17:31
  • 1
    @Brondahl the question is about embedding resources, and this is how to do it. :) The OP probably knows where to go from here. For others looking for how to do it, here's an example implementation related to testing with xunit: https://www.patriksvensson.se/2017/11/using-embedded-resources-in-xunit-tests – Johny Skovdal May 07 '19 at 08:23
  • 1
    The link from Johny no longer works, here is the archived version: https://web.archive.org/web/20201024173213/https://patriksvensson.se/2017/11/using-embedded-resources-in-xunit-tests/ – majjam Mar 08 '21 at 16:25
43

With newer versions of .Net Core - 2.0 or greater - there's a specialized class EmbeddedFileProvider that abstract the embedded file reading. To use it, add Microsoft.Extensions.FileProviders.Embedded package to your application:

dotnet add package Microsoft.Extensions.FileProviders.Embedded

The EmbeddedFileProvider allows you to create a stream reader, and use according to your scenario:

var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly());
using (var reader = embeddedProvider.GetFileInfo("yourfile.ext").CreateReadStream())
{
  // some logic with stream reader
}
  • 1
    This seemed promising, but I had issues with files in subfolders. I ended up going with my own matching logic off using `string[] names = assembly.GetManifestResourceNames();` that Luka mentioned above. – JackMorrissey Nov 20 '20 at 03:58
  • 2
    The file format for GetFileInfo() is "{Folder}.{filename}.{Extension}" WITHOUT the namespace. This is different to assembly.GetManifestResourceStream() which uses the file format "{Namespace}.{Folder}.{filename}.{Extension}" including the Namespace – JimbobTheSailor Feb 05 '21 at 22:07
  • I am getting a can't find resource error. I added the file to Images then changed the file type to embedded. var resourceName = "X_Signature.jpg"; using (var stream = assembly.GetFileInfo(resourceName).CreateReadStream()) { – Golden Lion Mar 07 '22 at 16:05
  • I set the resource file as an embedded resource and set a custom namespace.resources – Golden Lion Mar 07 '22 at 16:48
  • @JimbobTheSailor Your comment was so key to getting this to work. MS should add this to the method info page – KornMuffin Mar 14 '23 at 03:00
23

People have already generally answered this, so this is a rendering of the answers into something simple.

Before using the following, the file should be added as an embedded resource to the .csproj / project.json

Usage

var myJsonFile = ReadManifestData<Tests>("myJsonFile.json");
  1. Parameter: embedded filename name; Type: any class from the target resource's assembly
  2. looks for an embedded resource with that name
  3. returns the string value

Method

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();
        }
    }
}
activout.se
  • 6,058
  • 4
  • 27
  • 37
Dan
  • 12,808
  • 7
  • 45
  • 54
4

I have not confirmed this in documentation, but for me, it would appear the auto-generated Resource code that retrieves embedded files found in Resource.Designer.cs is now functioning again in .NET Core 3.1. I can now retrieve an embedded jpg simply by calling the Properties.Resources.MyImageName which returns a Bitmap object.

Rob
  • 101
  • 1
  • 4
  • streamreader retrieves characters only. This works if your resource file is character based – Golden Lion Jun 22 '20 at 21:28
  • Yes, this works now, but you need to add [System.Resources.Extensions](https://www.nuget.org/packages/System.Resources.Extensions) package and add `true` in cs/vbproj. but it's could cause some problems when used with .net framework projects. See [here](https://github.com/dotnet/msbuild/issues/4704) – fsbflavio Oct 16 '21 at 13:03
3

In dotnet 7, I needed to keep a text file as resource in a Razor Class Library project. To read that file I had to do the following -

  1. Add the file in csproj file
<ItemGroup>
  <EmbeddedResource Include="Resources/**/*" />
</ItemGroup>

Here, Resources is the folder I created in the Razor Class Library Project.

  1. Read the content of the file
private string ReadHtmlString()
{
    var embeddedProvider = new EmbeddedFileProvider(typeof(PageModelClass).Assembly);
    using var reader = embeddedProvider.GetFileInfo("Resources/filename.txt").CreateReadStream();
    using var sr = new StreamReader(reader);

    var content = sr.ReadToEnd();
    return content;
}

Here, PageModelClass is the Pages Model Class in the Razor Class Library.

th1rdey3
  • 4,176
  • 7
  • 30
  • 66