I am writing a C# application that uses a long "hard-coded" string.
For maintainability reasons I have decided to put this string in an external text file and load it. Is this a good idea? The extra I/O does not seem big in this case.
I realize that I also have an option to embed this file as a .resx resource. Is this a better idea? The file will never need to be localized.
If you intend to allow users/administrators to change the string, I agree with the other answers, and I'd suggest putting it in settings.
If you don't want it to be editable after deployment and it will only be modified by you and your developers, then I would put it in an embedded resource (note, this is not the same as a .resx file). You would read it at runtime like this:
Assembly assembly = Assembly.GetExecutingAssembly();
Stream stream = assembly.GetManifestResourceStream(“MyAssemblyNamespace.MyTextFile.txt”);
StreamReader reader = new StreamReader(stream);
string theText = streamReader.ReadToEnd();
Update: This is solution that is easy to maintain. The .txt file will just be another file in your solution explorer in Visual Studio and you can edit it just like any other file, keep it under source control like any other file, etc. To turn it into an embedded resource by changing the Build Action in the properties window to "Embedded Resource".
The end result is that your file(s) get embedded in your DLL so that you only have 1 DLL to distribute instead of a DLL and a folder of files that have to move around together.
Update 2: Regarding "production debugging", this is a very static solution, and so you won't be able to change the contents of the text file at runtime because the file is baked into the DLL at compile time. For reading the contents of the file, you can use tools like reflector to view the embedded resources of a DLL. You could also write a simple command line tool that dumps all the embedded .txt files from a DLL into individual files for you to look at.
For memory usage, there isn't a solution more efficient than "I load it from a file into memory only exactly when it is needed". You have to decide whether the improved maintainability and deployment is worth the cost of a little extra memory when your DLL is loaded into memory for your specific situation. That said, you haven't said how large these files are. If they are really huge (megabytes+), I would probably not use this solution and would go with loose files on the hard drive. If they are generally pretty small (hundreds of kilobytes), I wouldn't worry about the extra memory unless you are in some kind of embedded device situation where RAM is really tight.
Why not make it an appSetting in your web/app.config file?
<appSettings>
<add key="MyLongString" value="This is a really long string value that I don't want hardcoded" />
</appSettings>
Then, in code:
using System.Configuration; //To ease your typing pains
var myReallyLongString = ConfigurationManager.AppSettings["MyLongString"];
I would suggest to use Application Settings.
You can follow this MSDN link how to use Application and User Settings.
I would put this in an application configuration file.
Even better would be to add a Settings file to your project. You can then easily add configuration settings through Visual Studio.
See this link.
You could then access your string by using the following:
Settings.Default.MyString;
In addition, settings are strongly typed, so you don't need to do any conversions when you retrieve them.
To more directly answer your question, the "best practice" would be to use a resource file for any localizable (even if you're not going to localize it) string in your application. This allows you compile-time access to the string and keeps it from being externalized as a separate file to deploy with your application.
I suggest using this approach; settings are similar, but should not be used unless what you're storing there actually represents a setting. Constants are the other option, but in the case of a long string, I'd stay away from them, just for the sake of maintainability.
Related
This sounded like a trivial question initially but I did not come across any solid/best practice solution on how to do this so I am asking the question here. Now, let's imagine that we have to work with couple of ".txt" files in our code which is in a class library.
Now, I think there are 3 major ways to handle this:
Just put everything in your Bin/Debug/Resources folder of the calling application and in your code use "Resources\*.txt". I think this is the simplest and most unobtrusive way to handle this. However, there are many trivial problems with it:
When you check in the source control would not check-in the files inside the Bin/Debug folder
So in this case, probably adding the folder one level above and then writting post-build scripts is the most efficient option I guess?
Add resources folder on the same level as Bin folder. That way we can successfully manage it using the source control. however now when we need to reference it through our code it becomes tricky
We can reference this files assuming that the Binary folder's structure is like Bin/Debug and reference to the Resources folder like ..\..\Resources
But this structure is not always guaranteed what if the binary folder structure is like Bin/ (without any debug folder in it) then ../../Resources is going to fail
Add all the txt files as .RESX files. But I am not sure if it is the practice around everywhere and the most popular way to store resources.
-Also, the code that we have to write to access the resources files sounds like cumbersome as oppose to just picking up the file from windows file system.
Probably I am missing something trivial but I was just curious and was thinking that it should be much more simpler than this. Any suggestions?
Create a different project in the solution called Myproject.Resources.
Next install Microsoft MAT and manage your translations with MAT: https://developer.microsoft.com/en-us/windows/develop/multilingual-app-toolkit
You manage your translations with MAT and the .resx files are kept up-to-date. ;-)
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
When we follow localization guidelines we endup with at least a couple of resource files.
Resource.resx and Resource.CI.resx which is a specific CultureInfo resource.
Lets say we add a hundred string pairs in Resource.resx and want to translate those keys in another resource. we can copy paste them right now and translate them and it might work the first time.
However after we translate strings it becomes hard to keep files synchronized - it reorders strings automatically and I currently don't understand what is the supposed way to make sure each string is localized.
Since resource strings are supposed to be kind of linked with each other and with extra job that is done to make sure satellite assemblies are built correctly I was hoping theres a function like 'make sure each resource string is present in localized resource file' but I am afraid that one is missing..
RESX Synchroniser might do you what you are looking for
When you edit the .NET Resource files
in Visual Studio, either manually and
using the "Generate Local Resources"
command, the IDE updates only the
culture-invariant resources: if you
have a resource file called
Messages.aspx, the files in other
languages, say Messages.it-IT.resx,
are not updated, and you have to do
that manually. RESX Synchronizer will
help you keep the resource files
synchronized, adding the new keys to
the localized files, and removing the
deleted ones. Comments are preserved
during the process.
I just found http://zetaresourceeditor.codeplex.com/ as well seems like a similar idea to the others
may be UnitTest can help you? you know, which text each control should have, once you create them, after just add new strings to list and compare the values. after once hard working you can test your localization works right.
a little old this discussion, but still interesting. have a look at ResXManager
I know this has already been given traditional answers, but I would also like to put forward something completely original we tried (and succeeded) doing ourselves for more efficient localisation of Silverlight:
Localisation of Silverlight projects after completion
(Resx is so "last century")
I suggest you create culture specific resource files programmatically using the Resx file for that Winform.
You can create a small app which you could run time to time.
Create XML kind of file for each culture like fr.XML, fill that with the Union of all the strings in your project.And provide the translations there itself like, for example that file in french might look like the following..
< wordTranslation>
< Word>Hello< /Word>
< Translation>Bonjour< /Translation>
< /wordTranslation>
Create a hashtable or some data structure which would best act as dictionary for each culture, fill it with data from the culture specific XMl files like frDictionary.
For Each Resx file in your project for example wind1.resx , create a culture specific file like wind1.fr.resx.
Read words from wind1.resx, find the translation of the word from the frDictionayry.
Write it to wind1.fr.resx.
You can keep updating your translations in the XML file.
So its a one time effort.
This way you can keep it synchornised and easily maintainable.
You mean synchronize translations between those files? Use http://www.getlocalization.com and upload both as master files, when they are translated the translations are populated to all your files.
I think you can try Amanuens. It's developed by the same author of RESX Synchronizer and besides help keeping resource files synchronized (even automatically into your repository if you set it), can be used to give your translators access to strings to be translated in a very powerful and easy to use web editor.
If I include files in my Silverlight app and need to load them as raw byte arrays programatically, which Build Action should I set them as, and how do I refer to them? If they are included as Content, can I load them by path as a regular file? If I include them as Resource is there a collection of embedded resources where I can grab a reference to them? What are the pros and cons and differences between the two approaches?
Set the Build Action to "Embedded Resource" and use Assembly.GetManifestResourceStream to load them. I believe the "Resource" build action is meant for resource files (resx) which are slightly different, although I've never been entirely sure :)
If you include them as regular content, you may have difficulty deploying the files - I'm not entirely sure, to be honest. (That's a Silverlight-specific area.)
Personally I like using Embedded Resources so long as you don't need to be able to update them independently - at that point it's helpful to have them on disk as normal files.
i have an windows application that i have made by visual studio 2008.this application uses some graphical files such as jpeg.i make a setup for this appreciation but i worry about such files being modified by client.would you please help me how to protect those files ?
To detect such a tampering you should add your graphical files as resource within your application (or load from another assembly) and use Strong-Name signing. Even if it is not completely secure, it should prevent the most ones from altering your resource files.
You could embed the images into resource files that get included in the exe.
The easiest way is to use the images as a resource.
If you don't want to do that for any reason, then you could also calculate a cypher of the jpegs (maybe MD5) and check them against the one you previously stored in the code while loading the load program (form.load or whatever).
You could sign your files this way no one would be able to change the files without having your certificate.
this might be overkill and it depends on how mutch security you want else just place the images as resources.