Embedded Resource Name Loses Extension When File is Nested - c#

I have some scripts stored in files that I've marked as Embedded Resource. I nest each of these files under their associated .cs file. Unfortunately, for some reason, when you nest a file this way, the embedded resource name loses the file extension. This means that at runtime I have no way to identify which embedded resources are or aren't scripts. What can I do about this?
One thing I tried that did not work: getting the ManifestResourceInfo object, which has a FileName property. Unfortunately this property is null.
Another thing I tried was doubling up the extension. (like: filename.ext.ext). This didn't work, and everything after the first . is still missing.
I tried naming the resource with something very different, and noticed that the resource name didn't even change. It seems that it is generating the resource name for a nested embedded resource file based off of the "dependent upon" file, which in this case is just a regular .cs file. I tried doubling the extension of the .cs file to filename.extrastuff.cs but the resource name still doesn't change. It insists on clipping everything after the first ..
No, ok, I see now that it is actually naming the resource after the type defined in the .cs file, not the filename of either file. This is why the extension makes no difference. This means there is nothing I can do to either filename to help find the resource.

I discovered that the reason the file loses its extension is because for some reason when the file is nested, VS is naming the resource after the type instead of after the file.
The only thing I've found to allow me to still have an extension when nesting is to manually edit the .csproj file and add a LogicalName tag, which allows you to override the resource name.
<EmbeddedResource Include="Path\To\NestedFile.ext">
<LogicalName>NestedFile.ext</LogicalName>
<DependentUpon>ParentFile.cs</DependentUpon>
</EmbeddedResource>
Unfortunately, there is no IDE support for this, and the FileNesting extension I'm using doesn't support writing this tag either.
It's too cumbersome to have to do this for every file, so instead of relying on the file extension, I would have to do something like add an identifier inside my script files that identifies them as scripts.
Ultimately I realized that since in my case I'm validating script files from unit tests, I can simply scan the file system instead of the resource manifest and avoid this problem altogether.

Related

Creating localizatin .resx files makes empty .Designer.cs files

I'm trying to add localization to my .NET MVC project. As far as I've seen (here, here, and here), I should simply be able to create a total of three files (if I have two languages).
Resources.resx
Resources.en-us.resx
Resources.da-dk.resx
When I open the .resx files, I can add entries to them. Once I've done that (and set "Access Modifier" to either Internal or Public), it generates a Resources.*.Designer.cs file (as it should). However, for en-us and da-dk they are empty. No errors or anything.
As far as I could read (here, here, and here), I cannot have a dot between the file name and the .resx extension. And to my surprise, it's true. If I rename any of those en-us/da-dk files to Whatever.resx the Whatever.Designer.cs file will be created.
I've read a lot of answers, tried my way with T4 templates, and a bunch of other things, but I simply cannot get it to create a working Designer.cs file.
Am I doing it wrong? I feel like I've tried everything now. I just want to be able to do Resources.TestText and have my application do the translation depending on the culture.
It is by design.
The Resources.EN-US.resx file types, doesn't have a designer because the actual designer is in it's "parent" file, Resources.EN-US.resx. The en-us file only holds the key/value XML.
If you are calling your Resource, you probably use it like:
var someVar = Resources.SomeLocalizedString;
You don't have to differentiate between the EN-US types.
If you look at the designer's code, you can see whats happening (hold on, I'll fetch an example)
So, you don't need those designers, and it should work out of the box if you set the culture info of the UI thread.
Thread.CurrentThread.CurrentUICulture = new CultureInfo("EN-US");

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# writing to a file without full path

If I use this code
File.AppendAllText("C:/Users/Michael/Documents/Visual Studio 2010/Projects/PuzzleGame/PuzzleGame/PuzzleGameContent/player.TXT", "hi");
The file will save and add "hi" to the end of it. However, if I do something like this:
File.AppendAllText("player.TXT", "what is good?");
The file won't have a "what is good?" at the end of it. I can read files just fine using only the "player.TXT" filename but I can't write to a file using only that. Can anyone help me?
Your working directory is wherever the .exe is (unless you change it). So you see, when you compile, the exe ends up in the bin folder, so your player.txt would need to be there, not with your source.
edit:
I bet you're appending to player.txt THEN you read it and that's why it worked fine, because you created a new one in your bin folder. Otherwise, read would not have worked. If you go in your bin folder and delete player.txt, your readfile shouldn't work.
Both forms are perfectly valid. The likely scenario is that your second version is simply writing to a file at a different location, because not specifying the path will default to the current directory.
If you don't include a path, you'll want to ensure the current directory is valid for accessing the file.
Most likely there are two files on the file system, one in the directory that is explicitly defined in the first example and one where the executable is running in the second example since no explicit path was defined in the parameter of the method call.
From MSDN:
Given a string and a file path, this method opens the specified file,
appends the string to the end of the file, and then closes the file.
The file handle is guaranteed to be closed by this method, even if
exceptions are raised.
The method creates the file if it doesn’t exist, but it doesn't create
new directories. Therefore, the value of the path parameter must
contain existing directories
.
The problem is that AppendAllText is a method which will create the file if it doesn't already exist. So when you use an incomplete path it is unsure whether to create a new file in a base directory or add to an already existing file. If you can't use the full path for whatever reason, you could get the current working directory using something like:
File.AppendAllText(System.Environment.CurrentDirectory + "player.TXT", "what is good?");
So long as the current directory is correct, it'll work the same as your first working example.

Checking source file and automatically generating resx file

Hello everyone here is my problem. I have the source file of a web page and it will be translated into different languages, so there are lots of meta:resourcekey keywords everywhere as you can imagine.
What I want is a plugin in VS that will first create a resx file and then check the whole code and whenever it sees the "meta:resourcekey" it will add a new string in the resx and copy whatever it sees on the right of "meta:resourcekey"
Can anyone help?

Loading file in silverlight

I would like to load a custom file put as a resource file in my silverlight application, but the FileStream doesn't works (since I must stay in a partial trust environnment).
Is there any solution to load my file? (it is a binary serialized data).
UPDATE
Answer found :
I put my file as a "Resource" (not embedded neither content or anything else)
Loaded it like this :
StreamResourceInfo info = Application.GetResourceStream(new Uri(#"/Utilitaires;component/Resources/" + name, UriKind.Relative));
And then using the "info.Stream" property.
Now, I have an other asking. By doing like this, the file is added to the assembly (to the exe/dll), and make it a bit bigger.
But since these datas need to be loaded at the same time as the assembly, should I let them as a resource, or use another method to load them separatly? (and what should be the method? I need it to work in local as well as on a server).
Thanks,
KiTe
Since you need the resource at the same time as you load the assembly then the only other reason to place the file outside the Xap would be to allow the file to be modified without modifying the Xap.
Personally I would include the file as "Content" rather than "Resource". This means that the file ends up as an entry in the Xap (which is just a Zip file) rather than inside a dll.
You still use GetResourceStream to access it but the Url becomes something like:-
new Uri(#"/Assets/" + name, UriKind.Relative)
Where Assets is a folder you create in your project to store additional files, also name should include a file extension.
Using this approach kind of gives you the best of both worlds. The file is included in the Xap but if for some reason the file content needs to be modified the Xap can be opened as a Zip file and the file replaced.

Categories