Get file from RESW resource - c#

I have encountered a problem with retrieving a file for RESW file.
My project structure:
Levels
Level1.xml
Level2.xml
Level3.xml
Resources
LevelResources.resw
And files from "Levels" directory are added to "LevelResources.resw".
My try to retrieve content of those files:
var resourcesLoader = new ResourceLoader("LevelResources");
var item = resourcesLoader.GetString("Level1");
But the value of "item" is"
..\levels\level1.xml;System.String, System.Runtime,
Version=4.0.10.0, Culture=neutral,
PublicKeyToken=b03g5f6f12d40a6a;windows-1250
Why? This is not exactly what I expected (content of the file). How to retrieve content than?

The ResourceLoader class provides simplified access to app resources such as app UI strings.
When you dragging a file to the resource file, the data was stored as a file reference rather than the content, that’s why you will get result “level1.xml;System.String...”.
As a recommend way, I suggest you putting the file name as the key and the file content as the value in the *resw file so that you can use the ResourceLoader to get the content easily.

Related

Is it possible to embed binary data in a .NET assembly

Is it possible to embed binary data (as a resource, or by some other mean) in the C# assembly and then read the binary data from assembly during run-time and write it as a file.
I am making a DRM application and purpose is that the data must be hidden in the assembly as embedded resource, or a password protected ZIP file. So, I will try to embed the resource and if not possible then will look for a ZIP / UN-ZIP library with password protection to save DRM data.
I am writing a program in C# in which should have a binary data and it is added in the assembly during compile just like images, icons are added in assembly when we compile, and then when the assembly is executed by user then the binary data is read and saved as an external file.
Is it possible? then how to do it?
Yes. If you are using resources, you can include files too, which are represented as a byte array. Else you can include a file and set the Build Action to Embedded Resource, which include it as a resource too, which you can manually read.
public byte[] ExtractResource(Assembly assembly, string resourceName)
{
if (assembly == null)
{
return null;
}
using (Stream resFilestream = assembly.GetManifestResourceStream(resourceName))
{
if (resFilestream == null)
{
return null;
}
byte[] bytes = new byte[resFilestream.Length];
resFilestream.Read(bytes, 0, bytes.Length);
return bytes;
}
}
Then use it like this:
byte[] bytes = this.ExtractResource( Assembly.GetExecutingAssembly()
, "Project.Namespace.NameOfFile.ext"
);
yeah, its possible. Just add the file in the project, Select the file, Go to property and select Embedded Resource in Build Action property.
Here's the code=
private Stream GetStream(string fileName)
{
var asm = Assembly.GetExecutingAssembly();
Stream stream = asm.GetManifestResourceStream("NameSpace." + fileName);
return stream;
}
For clarification of sv88erik doubts-
as you can see in picture here, embedded resources are a part of the assembly itself and having a name as NameSpace.FileName
Background: When you build your application, the linked and embedded resource data is compiled directly into the application assembly (the .exe or .dll file).
To access the resources, use the class Resources contained in Resources.Designer.cs which is nested under the Resources.resx file in Solution Explorer. The Resources class encapsulates all your project resources into static readonly get properties. For example, a string resource “Bill” is accessed by Properties.Resources.Bill. You can access a Text file resource also as a string property. Binary files are referenced as properties of type byte[].
Double-click Resources.resx. Select Add Resource/Add Existing File and scroll to the file you want to be included.
For binaries, the class Resources has a property of type byte[] that is named after the included file. Assume the file name to be MyApp.dll, then the property should have the name MyApp. You find the exact name in the code file Resources.Designer.cs nested under the Resources.resx file in Solution Explorer.
You can access the resource as Properties.Resources.MyApp. For example, you can save the resource as a binary file with File.WriteAllBytes(PathAndName, Properties.Resources.MyApp);.

How does use XamlReader to load from a Xaml file from within the assembly?

I've found several posts across stackoverflow and the rest of the internet regarding how to load Xaml from a static file: they recommend creating a XmlReader or StreamReader pointing to a file found on the file system, but the .xaml document I would like to read from is going to be compiled with the rest of the assembly, so it won't have a meaningful file Uri. I do not want to copy this document around wherever the assembly goes. Is there a way to read from a .xaml document that has been compiled into the assembly?
I also know that I can simply read from a very long string literal inside the code itself, but I'd rather not do that - the UIElement produced from the Xaml should be easily edited, and I gain this by editing it in a Xaml file.
To illustrate what I'm hoping for, here's an example:
private void LoadUIElementFromCompiledXaml()
{
XmlReader xmlReader = new XmlReader("*Uri for .xaml document within my assembly*");
UIElement elementLoaded = (UIElement)XamlReader.Load(xmlReader);
}
I apologize in advance if the answer is blatantly obvious.
Before you can load Xaml from an assembly as an embedded resource, there is a bit of setup you must do. I'll walk you through an example, then from there you can customize it to suite your needs.
Create folder in your project. Name it XAML.
Add a XAML file to the XAML folder. Lets call it Sample.xaml.
Right-click on Sample.Xaml and choose properties. Set the value for Build Action to "Embedded Resource".
Right-click on the project and choose properties. Take note of the Default namespace value. We will use this as part of the path. For this example lets assume it is "MyNamespace.
Your code to load the Xaml resource would look something like this:
string defaultNamespace = "MyNamespace";
string folderName = "XAML";
string fileName = "Sample.xaml";
string path = String.Format("{0}.{1}.{2}", defaultNamespace, folderName, fileName);
using (Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(path))
{
object root = XamlReader.Load(stream);
}
As you can see the path to the resource is made up of the default namespace of the project, the folder path to the file, and the file name. If the folder path has multiple levels use dots as folder separator in place of back slashes. For example Xaml\Subfolder would be Xaml.Subfolder.

Access to Resources

I've C# project and it has Resources folder. This folder has some of txt files. This files have various file names.
I'm taking file names from any source as string variable. For example I have fileName string variable and test.txt file in Resources folder:
string fileName = "test.txt";
When I want to access this file as like below, I can:
WpfApplication.Properties.test.txt;
But, When I want to access it by this code, I can't.
WpfApplication.Properties.fileName;
I want to use fileName string variable and access this text file.
What can I do to access it?
Thanks in advance.
Edit :
I change form of this question:
I've string variable assigned any text file name. For example; I have a.txt, b.txt, c.txt, d.txt, etc.. I'm taking this file name as string variable (fileName) via some loops. So, I took "c.txt" string. And, I can access this file by code in below:
textName = "c.txt";
fileName = "../../Resources\\" + textName;
However, when I build this project as Setup Project and install .exe file to any PC, there is no "Resources" folder in application's folder. So,
../../Resources\
is unavailable.
How can I access Resources folder from exe file's folder?
You need to add a Resource File to your project wich has the extension .resx/.aspx.resx. You will then be able to double click on this file and edit the required resources/resource strings. To do this right click on Project node in Solution Explorer > Add > New Item > Resource File. Let us assume you have added a file called ResourceStrings.resx to the Properties folder and added a resource string with key name MyResourceString, to access these strings you would do
string s = Properties.ResourceStrings.MyResourceString;
I hope this helps.
I would strongly recommend you taking a look at: http://msdn.microsoft.com/en-us/library/aa970494.aspx
If your text files have build action set as Resource you can locate them in code like:
(assuming the file name is fileName and its located in Resources folder)
Uri uri = new Uri(string.Format("Resources/{0}", fileName), UriKind.Relative);
System.Windows.Resources.StreamResourceInfo info = Application.GetResourceStream(uri);
Then you can access info.Stream to get access to your file.

Bundle a folder with a .Net application

How can I bundle a folder with a one click application and reference those files/folders after?
Seems rather simple but I just can't figure out how.
As in, I had the file index.html in the folder UI and I wanted to package that with the application, then I want to get the stream for that file with the string "/UI/index.html" but instead of just index.html, an entire website.
Add the folder to your VS Project, right-click on it and select "embed as resource". That will make the files in the folder be embedded in the .NET assembly. To get the file contents in your program, you can use something like this:
public class ReadResource
{
public string ReadInEmbeddedFile (string filename) {
// assuming this class is in the same assembly as the resource folder
var assembly = typeof(ReadResource).Assembly;
// get the list of all embedded files as string array
string[] res = assembly.GetManifestResourceNames ();
var file = res.Where (r => r.EndsWith(filename)).FirstOrDefault ();
var stream = assembly.GetManifestResourceStream (file);
string file_content = new StreamReader(stream).ReadToEnd ();
return file_content;
}
}
In the above function I assume your files a text/html files; if not, you can change it not to return string but byte[], and use a binary stream reader for that.
I also select the files by file.EndsWith() which is enough for my needs; if your folder has a deep nested structure you need to modify that code to parse for folder levels.
Perhaps there is a better way, but given the content is not too large you can embed binaries directly into your program as a base64 string. In this case it would need to be an archive of the folder. You would also need to embed the dll used for unzipping that archive (If I understood correctly you want to have single .exe and nothing more).
Here is a short example
// create base64 strings prior to deployment
string unzipDll = Convert.ToBase64String(File.ReadAllBytes("Ionic.Zip.dll"));
string archive = Convert.ToBase64String(File.ReadAllBytes("archive.zip"));
string unzipDll = "base64string";
string archive = "probablyaverylongbase64string";
File.WriteAllBytes("Ionic.zip.dll", Convert.FromBase64String(unzipDll));
File.WriteAllBytes("archive.zip", Convert.FromBase64String(archive);
Ionic.Zip.ZipFile archive = new Ionic.Zip.ZipFile(archiveFile);
archive.ExtractAll("/destination");
The unzipping library is DotNetZip. It's nice because you need just a single dll. http://dotnetzip.codeplex.com/downloads/get/258012
Edit:
Come to think of it, as long as you write the Ionic.dll to the working directory of the .exe you shouldn't need to use the dynamic dll loading so I removed that part to simplify the answer (it would still need to be written before you reach the method it is in though).

Can't load a manifest resource with GetManifestResourceStream()

I've created a custom configuration section using XSD. In order to parse the config file that follows this new schema, I load the resource (my .xsd file) with this:
public partial class MonitoringConfiguration
{
public const string ConfigXsd = "MonitoringAPI.Configuration.MonitoringConfiguration.xsd";
public const string ConfigSchema = "urn:MonitoringConfiguration-1.0";
private static XmlSchemaSet xmlSchemaSet;
static MonitoringConfiguration()
{
xmlSchemaSet = new XmlSchemaSet();
Stream xsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ConfigXsd);
XmlReader schemaReader = XmlReader.Create(xsdStream);
xmlSchemaSet.Add(ConfigSchema, schemaReader);
}
}
By the way my resource is: MonitoringConfiguration.xsd. And the namespace of the other partial class (that represents the code behind of the .xsd file) is MonitoringAPI.Configuration.
The problem is situated here:
Stream xsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ConfigXsd);
The xsdStream is null, so I guess the resource can't be found! But why?
Thank you
The name of the resource is always:
<Base namespace>.<RelativePathInProject>.<FileName>
So if your resource is located in "Resources/Xsd/", and your default project namespace is "MonitoringAPI.Configuration", the resource name is:
"MonitoringAPI.Configuration.Resources.Xsd.MonitoringConfiguration.xsd"
Also make sure the build action for your resource is set to "Embedded Resource"
Easy and correct way to get the actual name of your embedded resource:
string[] resourceNames =
Assembly.GetExecutingAssembly().GetManifestResourceNames();
Then simply check resourceNames array, and you will know for sure what to pass to GetManifestResourceStream method.
In my case,
When you try to access the file via GetManifestResourceStream(). You will get an error due to invalid path of the file, and stream will be null.
Solution:
Right click on the file which you have added in to solution and Click on Properties.
Select the Build Action as Embedded Resource. (Instead of Content - by default)
By default, visual studio does not embed xsd file therefore you must ensure "Build Action" property of xsd file is set to "Embedded Resource" to make it works
just add your resources under form1.resx -->add existing items
double click on the resources you added under Resources folder.go to properties and select "Embedded Resources" instead of none.
Then
try debugging the line:
string[] resourceNames=Assembly.GetExecutingAssembly().GetManifestResourceNames();
check the resources you added are in the array. then copy the resource name exactly from this array and try putting the name on your code..it works fine!!
You can get the Resource Stream by passing the Resource Names which is as follows below...
Get the resource name e.g..
Assembly objAssembly = Assembly.GetExecutingAssembly();
string[] strResourceNames = objAssembly.GetManifestResourceNames();
Pass the Resource Names to ...
Stream strm = objAssembly.GetManifestResourceStream(strResourceNames);
Now you have Stream you can do whatever you want...
In my case, it was something completely different:
My UWP App compiled correctly in Debug and Release configuration but GetManifestResourceStream returned Null only Release configuration.
The issue was, that in the UWP Build Configuration file (and only there) the setting "Compile with .NET Native tool chain" was enabled. After disabling, GetManifestResourceStream worked as expected.
I had an issue where I was embedding a whole heap of .xsd files in many different assemblies; everything was working (GetManifestResourceNames was returning the files I'd expect to see) except for one. The one which wasn't was called:
Something.LA.xsd
I wasn't dealing with specific cultures and the .LA bit at the end of the filename was being picked up by the compiler as this file being for the LA culture - the filename in the manifest was going in as Something.xsd (under culture LA) - hence me not being able to find it (it ended up in a satellite assembly). I dodged the issue by renaming the file - presumably it is possible to explicitly state the culture of a given embedded resource.
Actually, a quick google reveals:
How can I prevent embedded resource file culture being set based on its filename
According to this answer, you've got to do hacky things - so perhaps renaming the file wasn't so bad after all :)

Categories