I'm using VS Code under Linux (Debian Buster) and currently write some unittests using the MSTest-framework. Some of my tests have to read files that I have stored in my Test-project NewAppTest. UnitTest1.cs needs to read some_data.json, directory structure:
NewAppTest
+ UnitTest1.cs
+ some_data.json
In UnitTest1.cs I use this code to read some_data.json:
[TestMethod]
public void GetEmployee()
{
var data = File.ReadAllText("../../../some_data.json");
Assert.IsNotNull(data);
}
It bugs me that I need to prefix the filename with "../../../". Surely there must be a better way to set the current working dir. I googled some and found this and this, but I don't understand it.
I would like to create a file like said .runsettings where I specify the current working directory for all my tests in the project.
I would rather not have to touch every testclass.
A sample minimal .runsettings befitting my use case would be nice.
A good way to include files in your test application is to use embedded resources. Embedded resources are bundled with the test build so they're independent of its location.
To embed a file, edit your .csproj file and add the following item group (as a child of <Project>):
<ItemGroup>
<EmbeddedResource Include="some_data.json" />
</ItemGroup>
(If some_data.json is in a subfolder within the project, the path would be subfolder/some_data.json).
To read an embedded resource, use GetManifestResourceStream:
var assembly = typeof(UnitTest1).Assembly; //Get the assembly in which the resources are embedded
using Stream stream = assembly.GetManifestResourceStream("NewAppTest.some_data.json");
//Read the data from the stream as a string
using StreamReader reader = new(stream);
string data = reader.ReadToEnd();
Thank you, this worked well. For all who are reading along:
I also created a subfolder named "subfolder" in the Test-Project and put some_data.json and more_data.json in there:
subfolder\
+ some_data.json
+ more_data.json
In the csproj I added this to include all files:
<EmbeddedResource Include="subfolder/*.*" />
In the TestMethod I used this to read the files:
var assembly = typeof(UnitTest1).Assembly;
using Stream stream = assembly.GetManifestResourceStream("NewAppTest.subfolder.more_data.json");
This way you don't need to edit your csproj when you add new data files for your tests.
I am trying to set a stream equal to the text content of an embedded resource in my ASP.NET Core project. However, when debugging, the stream is continuously being set to null, and I assume that this is because of the fact that it cannot find this embedded resource to begin with.
I have set the file as an embedded resource by going to Properties > Build Action > Embedded Resource. And then I have also edited the projects .csproj file to include an item group which references the file to include:
<ItemGroup>
<EmbeddedResource Include="Assets/loyalty-template.html">
<LogicalName>Assets/Loyalty-template.html</LogicalName>
</EmbeddedResource>
</ItemGroup>
Where I set the stream:
string body;
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Assets/loyalty-template.html"))
{
TextReader tr = new StreamReader(stream);
body = tr.ReadToEnd();
}
Am I referencing the embedded file correctly in the GetManifestResourceStream? Below is the file structure of my project where loyalty-template.html is situated:
Use the following path: [assembly name].[directory].[file name].
OR
Use GetManifestResourceNames with the file name and extension only:
string resourceName = assembly.GetManifestResourceNames()
.Single(str => str.EndsWith("loyalty-template.html"));
firstly apology if this has already been answered and I am duplicating the question. I have tried to find the answer to my issue but have failed and none of the auto-suggestions answers my problem.
I have my main project (XAML) and also a class library project called FileStore for files. The class library project is referenced into the main project and I have images and icon file in the class library project that I can access with no issues in my main project, however, I struggle to get the content of a txt file from the CL project to display in a label on the main project. I get the error: the system could not find the file and from the error, I can see that it is trying to look for a file in the main project bin\debug folder
I tried to follow this previous post which seemed to partly answer my issue but to no avail sadly.
Get relative file path in a class library project that is being referenced by a web project
The txt file Build action is set to: Resource and Copy to Output Directory set to: Copy Always.
As I mentioned I have the FileStore project referenced in my main project and the images work fine.
Below is the code I am using, I have tried different variations such as:
\Resources\textFile.txt and \textFile.txt, still no luck.
'''
public static string ReadFileinClLibr()
{
var buildDir =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var filePath = buildDir + #"\textFile.txt";
return File.ReadAllText(filePath);
}
'''
For comparition here is the path for the image files that works, but I cannot get it to work with the txt file, as the error reads: the given paths format is not supported..
'''
#"pack://application:,,,/FileStore;component/Resources\textFile.txt"
'''
I want to be able to input the content of the text file from the class library project to the label in the main xaml project.
At the moment compiler keeps looking for this file in a debug folder of the main project, what I want is, for the compiler to look for the txt file in a CL FileStore project
In order to access the file all the time, we have to have the file copied to the debug folder. Right click the file from solution explorer change the properties then try to access the file from the executing assembly location.
StringBuilder bodyContent = new StringBuilder();
string fileName = "myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
}
catch(Exception ex)
{
Console.WriteLine(String.Format("{0} # {1}", "Exception while reading the file: " + ex.InnerException.Message, DateTime.Now));
throw ex;
}
Thanks to the post from #Sreekanth Gundlapally I have managed to fix my issues. I have mostly drawn on from the answer provided by #Sreekanth Gundlapally but there is one important bit missing. The string fileName should include any subfolders that the resource file is within in the Class Library Project, for example in my case the folder was named 'Resources' so the code should look like this:
string fileName = #"Resources/myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
I have also cleaned and rebuilt solution after which it all worked a charm.
Also a side note, anyone trying this and getting funny characters make sure your file's encoding is set to UTF-8 as this is the default encoding used by StreamReader, otherwise your file content may not be read correctly if it contains signs such as apostrophe.
This is a C# .NET 4.0 application:
I'm embedding a text file as a resource and then trying to display it in a dialog box:
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyProj.Help.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
string result = reader.ReadToEnd();
System.Windows.Forms.MessageBox.Show(result, "MyProj", MessageBoxButtons.OK);
}
}
The solution is MyProjSolution and the executable is MyProj.exe. Help.txt is an embedded resource. However, the stream is null. I've tried MyProjSolution.Help.txt and MyProjSolution.MyProj.Help.txt but nothing seems to work.
You can check that the resources are correctly embedded by using
//From the assembly where this code lives!
this.GetType().Assembly.GetManifestResourceNames()
//or from the entry point to the application - there is a difference!
Assembly.GetExecutingAssembly().GetManifestResourceNames()
when debugging. This will list all the (fully qualified) names of all resources embedded in the assembly your code is written in.
See Assembly.GetManifestResourceNames() on MSDN.
Simply copy the relevant name, and use that instead of whatever you have defined in the variable 'resourceName'.
Notes - the resource name is case sensitive, and if you have incorrectly embedded the resource file, it will not show up in the list returned by the call to GetManifestResourceNames(). Also - make sure you are reading the resource from the correct assembly (if multiple assemblies are used) - it's all too easy to get the resources from the currently executing assembly rather than from a referenced assembly.
EDIT - .NET Core
Please see this SO post for details on how to embed using .NET Core.
Retrieving the manifest info looks to be similar - just use this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames() to get the a manifest from the assembly where the code is executing.
I haven't figured out how to do the equivalent of Assembly.GetExecutingAssembly() in .NET Core yet! if anyone knows - please let me know and I will update this answer.
I had a similar issue check first that the file is included in your project , then go to properties and set the build action of that file to Embedded Resource . this worked for me .
The embedded file's "Build Action" property should be set as "Embedded Resource" to run the line, which is given below, properly:
Stream stream = assembly.GetManifestResourceStream(resourceName)
Right click on the file, click the property and then set "Build Action" property as "Embedded Resource":
Here is the cause of my null value.
http://adrianmejia.com/blog/2011/07/18/cs-getmanifestresourcestream-gotcha/
The GetManifestResourceStream method will always returns NULL if the resource ‘built action‘ property is not set to ‘embedded resource‘
After setting this property with all the needed files assembly.GetManifestResourceStream starts returning the correct stream instead of NULL.
Just a warning.
I could not access my file as an embedded resource even though I specified that it was and even though it had that Build Action property. Wasted a lot of time banging my head. I embedded a csharp code file with .txt appended to its name (xxx.cs.txt). For some reason the GetManifestResourceNames() and GetManifestResourceStream() methods won't see a file with .cs in its name.
I renamed it simply xxx.txt and everything was fine.
Weird.
In my case the problem was that the code looking for the resource was in a different project that the resource itself.
You can only access resources that are in the same project the code is. I thought I could put all my resources in the web page project, but I need images in the mail project too.
Hope this helps someone in the same situation I was.
I find really useful calling Assembly.GetExecutingAssembly().GetManifestResourceNames();.
I had the same problem, thanks to Jay I found it was hyphens in the directory name.
ProjectName.ResourceFolder.Sub-Directory becomes ProjectName.ResourceFolder.Sub_Directory when you reference the resource stream.
A simple and streamlined solution is to have this base class:
public class EmbededResourceReader
{
protected string LoadString(string fileName)
{
return LoadString(fileName, Encoding.UTF8);
}
protected string LoadString(string fileName, Encoding encoding)
{
var assembly = this.GetType().Assembly;
var resourceStream = assembly.GetManifestResourceStream($"{this.GetType().Namespace}.{fileName}");
using (var reader = new StreamReader(resourceStream, encoding))
{
return reader.ReadToEnd();
}
}
}
Then, when you add a resource, you create a reader C# class in the same folder:
where the reader class MyResource.cs is very simple:
public class MyResource : EmbededResourceReader
{
public string LoadString() => LoadString($"{nameof(MyResource)}.txt");
}
So, each resource will have a "shadow" class that knows how to read it properly.
This is how you read the resource in your code:
var text = new MyResource().LoadString();
And as other answers suggested, do not forget to set "Embedded Resource" in the Build Action property of the resource file.
The advantage of this uniform solution is
less hassle with finding correct full name of the resource, especially when placed in nested folders
in case when folder is renamed OR Default Namespace in project settings is changed, the code will NOT break
In case it helps anyone else, Make sure Assembly.GetExecutingAssembly() line is called from same assembly which has embedded resources.
First Unload the project and click on edit the project file.
Inside the project file make sure that the item you are fetching from the assembly is included inside <EmbeddedResource> tag.
Eg:
<ItemGroup>
<EmbeddedResource Include="Template\ForExampleFile.html" />
</ItemGroup>
The files I added into the project were just in Content tag but not in the EmbeddedResource as shown below by default. Hence the stream was returning null.
<ItemGroup>
<Content Include="Template\ForExampleFile.html" />
</ItemGroup>
You need to unload your solution.Then edit project.Afterfind your folder and change like this:
<EmbeddedResource Include="yourpath" />
Although OP got GetManifestResourceStream returning NULL from resources in the same Assembly, some Answers suggested that when Resources are in another Project or Assembly they cannot be retrieved, and are a fair cause of GetManifestResourceStream returning NULL.
This is not true, at least since 2011; as I pointed in some comments elsewhere, Assembly.LoadFrom() or typeof do the trick and as a result you can access resources that are in another project.
I have a moderately complex example here to illustrate; this is my test setup:
Path to another project:
Captured here:
var sharedXMLResource =
"D:\\My Documents\\Consultório Impressos\\DB Pacientes\\Teste\\TestesVariados\\WinFormFramework\\Read_Embedded_XML_File_CS\\bin\\Debug\\Read_Embedded_XML_File_CS.exe";
And on Form1.cs from WinFormFramework I specify with
Namespace.Folder.Resource
like that:
StreamReader reader =
new StreamReader(Assembly.LoadFrom(sharedXMLResource).GetManifestResourceStream("Read_Embedded_XML_File_CS.SharedResources.ContactList.xml") ?? throw new InvalidOperationException());
And the result displayed at textbox:
I spent several hours to get it right; for that, I had to use a lot these at Immediate Window:
Environment.CurrentDirectory
AppDomain.CurrentDomain.BaseDirectory
System.Reflection.Assembly.GetExecutingAssembly().Location
System.Reflection.Assembly.GetAssembly(typeof(WinFormFramework.Program)).Location
Hope it helps someone
I know this is an old question, however, I stumbled through this and with the help of #Jay answer I was able to get this working.
I had to use the full filename to get this to work.
using var stream = assembly.GetManifestResourceStream("Project.Folder.appsettings.json");
You probably need to specify the path to your txt file in the GetManifestResourceStream parameter, or you could try sticking the txt file in the same directory as your executable. Hope that helps!
I have created a full project which works perfectly. My problem concerns the setup project. When I use it on another computer, the text file cannot be found even if they are inside the resource folder during the deployment!
How can I ensure that my program will find those text files after installing the software on another computer!
I have been looking for this solution but in vain. Please help me sort this out. If I can get a full code that does that i will be very happy!
FIrst set the build action of the text file to "EmbeddedResource".
Then to read the file in your code:
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "AssemblyName.MyFile.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
string result = reader.ReadToEnd();
}
}
If you can't figure out the name of the embedded resource do this to find the names and it should be obvious which your file is:
assembly.GetManifestResourceNames();
This is assuming you want the text file to be embedded in the assembly. If not, then you might just want to change your setup project to include the text file during the installation.
Assuming you mean that you have a file in your project that you've set as an EmbeddedResource, you want
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(path))
{
...
}
where path should be the assembly name followed by the relative path to your file in the project folder hierarchy. The separator character used is the period ..
So if you have an assembly called MyCompany.MyProject and then in that project you have a folder Test containing Image.jpg, you would use the path MyCompany.MyProject.Test.Image.jpg to get a Stream for it.
create this function to read whatever embedded resource text file you have :
public string GetFromResources(string resourceName)
{
Assembly assem = this.GetType().Assembly;
using (Stream stream = assem.GetManifestResourceStream(resourceName))
{
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}