.net Resource DLL with multiple resx files - c#

I need to know the way to properly access strings and images from a resource DLL that has multiple resource files (.resx).
I have a very large project that I am working on and is composed of several winforms each with multiple panels. I am trying to tidy things up a bit by making each form has its own res file and limit the application to one resource DLL instead of multiple resource DLLs.
The problem is when I try and add a new resource file to my resource DLL and try to access a string, for example, that is being saved in the newly created resx file. ResourceManager return a null string.
Here is how I am creating my ResourceManager object and getting the string
static public string GetResourceString(string sStringName)
{
System.Reflection.Assembly myDllAssembly = System.Reflection.Assembly.LoadFile(ResPath);
string[] allResourcesinDLL = myDllAssembly.GetManifestResourceNames();
ResourceManager ResInstance = new ResourceManager(allResourcesinDLL[0].Replace(".resources", string.Empty), myDllAssembly);
return ResInstance.GetString(sStringName);
}
Where ResPath is the path to my resource DLL and sStringName is the resource/string title.
I Am not sure if there is a way to specify the resx file to read from or if it should be handled in some other way. Please bear in mind that my application is compiled using the .net 2.0 framework so I am kinda limited to the APIs that I am able to use.

Related

net core 2.0 read file added as resources

I am doing a C# Net Core 2.0 Application...
I have a .sln with several Console projects called PrjA, PrjB, PrjC that will be run in differents ports, port 5000, port 5010, port 5020. They are running in parallel by Console
C:>dotnet PrjA.dll
C:>dotnet PrjB.dll
C:>dotnet PrjC.dll
I have another Library Project called PrjCommon that it is referenced by all three Project. In this Project I want to have a configuration file in common to all three projects.
this file is a json file called portsettings.json.
When i run any of those projects in Debug mode or generating the Publish folder, portsettings.json file is not saved.
In PrjCommon Project I tried to embebed portsettings.json as a file in Resources.resx.
From any of these three projects, I called a Method in PrjCommon that should read portsettings.json file.
I have tried to read this file from Resources.resx in two ways.
First like this
var assembly = Assembly.GetEntryAssembly();
string[] names = assembly.GetManifestResourceNames();
but names is null.
And Second
var byteArray = Resources.portsettings;
That return a bytes arrays, but i can not transform those byte array into json.
My questions is how can I make it Works. Either to save json file when I Compile those Projects, or, to save it as resources file and be able to read it.
Thanks
You could read the embedded resources with the following.
public static class EmbeddedResource
{
public static string[] GetApiRequestFile(string namespaceAndFileName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(namespaceAndFileName))
using (var reader = new StreamReader(stream, Encoding.UTF8))
return reader.ReadToEnd().Split(';');
}
catch(Exception exception)
{
ApplicationProvider.WriteToLog<EmbeddedResource>().Error(exception.Message);
throw new Exception($"Failed to read Embedded Resource {namespaceAndFileName}");
}
}
}
So, in my case I want to read embedded text files that contain URL's that I format, they act as a template primarily. But the logic you're seeking would be that first stream line.
Solution - Opti
Folder - Resource
File - RequestUrl.txt
If I had a class where the text file is, the namespace with the specified file would be Opti.Resource.RequestUrl.txt.
I solved saving json file in Debug and Publish directory by setting .json file property Copy to Output Directory to Always as says here.
I have also add Resources file following this tutorial
I do not if it the best way, but it is the simplest.

Using external resx files (not embedded) at runtime in C#

I have an application where users can define custom elements by adding their own xaml files. These files are loaded by the application on startup. The idea is to be able to extend the application without having to recompile it. These elements will be shown on screen to the user, and the xaml files may contain resource keys which are not included in the resx files of the application itself. So I have a requirement to have separate resx files which the user can edit, that will also be loaded at runtime.
I've looked at the ResourceManager class, and I know that it can be set to access resources from various other assemblies. But from what I gather the resources must be part of an assembly, which is precisely what I don't want. What I want is to have a bunch of files like these:
%ProgramData%\MyApplication\Resources\strings.resx
%ProgramData%\MyApplication\Resources\strings.de-DE.resx
%ProgramData%\MyApplication\Resources\strings.zh-CN.resx
and I want my application to be able to load these files and access the strings in them.
This article https://msdn.microsoft.com/en-us/library/gg418542(v=vs.110).aspx shows two approaches using ResXResourceReader and ResXResourceSet. However, it appears that these classes take a path to a specific file (or a stream), and therefore won't be able to pick the correct file according to current culture and the naming convention. I know I can code this myself, and that's what I'll do if I don't find a better solution. But ideally I'd want something that handles this for me. For instance if it would be possible to point a ResourceManager to a folder instead of an assembly. Is something like this possible?
after a long long searching i found this:
If i understand you in the right way you want to create user defined forms in WPF at runtime using xaml.
I am not sure but, i think the resource files will not help you out, because all xaml forms precompiled in the assembly. I found something that maybe sounds like a solution for your problem. Its called Sattalite Assembly. In the first step you have to create a new resource file. Second step is to link it with the Assembly Linker (Al.exe). form .net Framework. MSDN Creating Satellite Assemblies
First step create a ResourceFile at Runtime (here a little help)
public static void CreateResourceFile()
{
string resourceFileName = "externeresource";
System.Xml.XmlDocument xmldoc = new XmlDocument();
XmlTextReader reader = new XmlTextReader("/runtimeWPForm.xml");
reader.WhitespaceHandling = WhitespaceHandling.None;
xmldoc.Load(reader);
ResourceWriter resourceWriter = new ResourceWriter(resourceFileName);
/*Add XmlDocument must be Serializable to store it in
resourceWriter.AddResource("xamlgrid", xmldoc.ToString());
the Resource, so i stored a String here. (not testet)*/
resourceWriter.Close();
MessageBox.Show("File " + resourceFileName + " created");
reader.Close();
}
Second step create a Sattlelite Assembly from resource file with Assembly Linker Al.exe
Last step is to load the xaml Forms from the Sattalite Assembly (here a little help)
Uri GridUri = new Uri(/*Note1*/, UriKind.Relative);
Windows.Resources.StreamResourceInfo sri = Application.GetResourceStream(GridUri);
System.Windows.Markup.XamlReader xrdr = new System.Windows.Markup.XamlReader();
Grid grd = (Grid)xrdr.LoadAsync(sri.Stream);
this.Content = grd;
Note1:
Resource file - referenced assembly Pack URIs in WPF
Uri uri = new Uri("/ReferencedAssembly;component/ResourceFile.xaml",UriKind.Relative);
Here some usefull Information as i think Construct XAML Forms at Runtime with Resource Files
This is all i found for you and no guarantee for functionallity.
Im interested in if this will work for you, so please send an answer on success or if you solved your issue.
PS.: if this works i think you only have to restart you main application to load the new sattalite assembly. Maybe you have to start an ohter application that do the job and after finish automaticly start your main app again.
Best reguards
GatewayToCode

Can we skip ResourceManager?

I've working on a project where I'm using ResourceManager extensively and this question just crossed my mind.
Can we read from .resx files without using ResourceManager? I mean, is there another way?
ResourceManager is a convenience class, it works very well with the way the build system supports .resx files. No, it is not a strict necessity.
A .NET assembly has the generic capability of embedding arbitrary data into the manifest of the assembly. Just a blob of bytes, it can be anything you want. Directly supported by the build system as well, just add a file to your project and set its Build Action to "Embedded Resource". At runtime, you retrieve the data in that file with Assembly.GetManifestResourceStream().
You can stop right there, but that's just a single file, it doesn't scale very well if you have many small resources you want to embed. Which is where a .resx file starts, it is an XML file that contains resources in a friendly format. One that gives you a fighting chance to recover the source again when the original got lost.
But an XML format is not a very good format for resource data, it is bulky and it is expensive to find data back. So .NET has resgen.exe, a build tool that turns the XML file into a binary file, a .resources file. Compact and easy to find stuff back. And fit to be embedded directly as a single manifest resource.
What you don't want to do is having to read the .resources data yourself. You'll want to use a helper class that can find specific resources back from the blob of bytes. You want use the ResourceReader class, its GetResourceData() lets you specify the resource name and it will spit the resource type and data back out.
You can stop right there, but an app often has a need for different sets of resources. A very common localization need. Which is what satellite assemblies are all about, different assemblies that contain nothing but resources, each for a specific culture. They are separate so you don't pay for the virtual memory that's required to store all the localized resources when you need only one set of them. What's needed here is a helper class that automatically locates and loads the correct satellite assembly and retrieves the resource for you, based on the current culture.
That helper class is ResourceManager.
If you choose to skip the use of the ResourceManager you can let Visual Studio handle code generation for you. Ultimately the generated code uses a ResourceManager, but you're no longer writing that code manually. Additionally, you get compile-time checking since you're referencing a generated static class.
If you add a resource file to your project and double click it from the Solution Explorer, Visual Studio presents you with a dialog where you can enter a name for a resource, and its value. The dialog presents you with options to add resources as strings, images, audio, etc. (look at the dropdowns at the top of the dialog). Next, to get the code generation bit, you need to set the Access Modifier to either "Public" or "Internal". The third option is "No code generation."
For example, add a resource file called "MyResources", then add a string resource with the name Greeting and a value of Hello! With one of the former two options selected for code generation (start off with public to test it, restrict the access as needed), you should now be able to reference the resources from your code via MyResources.Greeting. If you don't see it right away, make sure you've saved the file and try compiling.
string greeting = MyResources.Greeting; // "Hello!"
If you add other resource types (image, audio, etc.) then the return types will differ, of course.
At this point you could inspect the generated .cs file and see that the generated code is using a ResourceManager. The other use for resource files is localization. Let's say you wanted a Spanish version of MyResources. You would add a new file called MyResources.es.resx, where es corresponds to the language code desired (Spanish in this case). Now add the same resource name of Greeting with a Spanish value of Hola!.
If you change the thread culture to Spanish, referencing the resource will now return the Spanish version:
string defaultGreeting = MyResources.Greeting; // "Hello!"
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
string spanishGreeting = MyResources.Greeting; // "Hola!"
Note that you only really need to set the access modifier to one of the code generation options for your default resource file (i.e., MyResources.resx), not for all the other localized versions you add. There's no harm in doing so, but in my opinion it's cleaner to have the main file generated while the others just have the resource values desired without code generation.
Well, Resources are compiled into the assembly. You could try to read the assembly by reading the bytes (or the IL), and extract the resources from there.
ResourceManager does this all for you, so I could not think of any reason you want to do this... Maybe one, if you don't want to load the assembly in memory, you could do it without ResourceManager.
Ref Microsoft: Represents a resource manager that provides convenient access to culture-specific resources at run time.
I expect, I'd you use multi Lang, you will get a more consistent result and better compatibility.
IMHO

c# - where to place txt files

I'm working on a simple progam, and part of it populates a list from a txt file.
this probably is not a smart question but, I didn't find any info on this.
I was wondering where is the best place to put text files in the application directory.
O know about the Resouces but, I wasn't able to get the path of the file I stored there.
so 2 questions:
where is the best place to put a txt file? (or any other importent file to use in the application)
if I put files in the Resources how do I get its path ?
(sorry fo my English)
If these are files that you do not need to expose to the users and only serve an internal purpose, then you can embed them in your assembly as resources, and extract them when you need them.
To do this, create a new directory in your application. Let's call it 'Resources'. Then, add text files to it. Use the properties window of each text file to change the BuildAction setting to "Embedded Resource". Then, in your code once you need the contents of the file you can use code like this to extract it:
using System.Reflection;
// ...
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApplication.Resources.MyFile.txt")) {
using (StreamReader reader = new StreamReader(stream)) {
string contents = reader.ReadToEnd();
// Do stuff with the text here
}
}
If you don't want to do this, the correct location to place files is in a directory you create under the AppData directory. This is a known system path, which you can obtain like this:
string folderLocation = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string myPath = Path.Combine(folderLocation, "MyAppName");
You can then use a StreamReader or other class in System.IO to find/enumerate and read the files.
When an application has associated/companion data files it sometimes makes sense to embed them as a Resource, because then there is less chance for them to be tampered with e.g. deleted, or the data modified.
And other times it makes sense to keep the file loose....so you have to decide the best place to store them....you can locate these in the place where the application is installed, or in the Application Data/AppData directory.
For embedding files in Resources have a look at this link:
http://support.microsoft.com/kb/319292
It has a step-by-step guide showing how to embed a file (e.g. a Text file into Resources), and then using a StreamReader to access it and read its contents.
To store the files and access them from a suitably located directory you can use:
System.Environment.SpecialFolder.ApplicationData
with
Environment.GetFolderPath()
to find out where the AppData directory is.
Then when you create your application Setup/Installer, you should get it to create a directory for your application underneath AppData, and then you can decide what files you want to be installed into that location.
See:
Saving a file to Application Data in c#
Note, ApplicationData "roams"...i.e. when you logon to a different machine, the files are transferred onto that machine as part of your profile....you may not want this....so you could instead use:
System.Environment.SpecialFolder.CommonApplicationData

How can a file based ResourceManager fall back to the embedded resources?

Our winforms application needs to be able to distribute ad-hoc translations in the *.resource format and use these in preference to the embedded translations. Is there a way to acheive this fall back strategy?
Why the *.resource format. The .Net pattern is to use localised DLL files. See http://msdn.microsoft.com/en-us/goglobal/bb688110.aspx
I've created a new class that can contain two ResourceManagers. These can be both a file based ResourceManager for the ad-hoc *.resource files and an assembly based ResourceManager for the embedded resource files.
If the ad-hock mode is enabled then the primary ResourceManager is file based with the second ResourceManager as an assembly based one used in a catch block as a fall back.
If the ad-hoc mode is dissabled the primary ResourceManager is an assembly based one and there is no secondary ResourceManager.

Categories