ResourceManager not picking up correct resx file - c#

I am having an issue getting the correct resource file entries and need some help ... here is my scenario
I have a series of projects that are a part of a large reporting solution that follow this format
Plugin.****Report
Reference (folder)
DataAccessLayer (folder)
DataSets (folder)
DataWrappers (folder)
Localization (folder)
*.cs
Where * is the name of the report I am going to generate
The *.cs has an export statement so that I can pick it up using MEF (not sure if this is relevant, but thought it worth mentioning). The namespace in *.cs is CompanyName.DataShaper.Plugin.*Report. Due to the project name, and location of the files, I changed the default namespace for each project to be CompanyName.DataShaper.Plugin.*Report (it was just Plugin.*Report before my change).
Now for the problem .. inside of *.cs I am instantiating a ResourceManager. That looks like this ...
_resourceManager =
new ResourceManager("CompanyName.DataShaper.Plugin.*Report.Localization.*Report",
Assembly.GetExecutingAssembly());
inside my resx designer file I have the following ...
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CompanyName.DataShaper.Plugin.*Report.Localization.*Report", typeof(*Report).Assembly);
resourceMan = temp;
}
return resourceMan;
}
My call to the resource manager looks like this ...
string resourceString = _resourceManager.GetString(resourceKey, _currrentCultureInfo);
where _currentCultureInfo is a a correct CultureInfo object.
I have 4 different resx files in my Localization folder for each project, (****Report.resx, ****Report.fr-ca.resx, ****Report.en-gb.resx, ****Report.de-de.resx).
When I make the call to the resource manager, I always get the entry from the .resx ... never any of the other language files, regardless of the CultureInfo object I pass into the call. What have I messed up?
--> Quick update to my original question, but this does appear to be MEF related. I instantiated my class the old fashioned way (new *Report()) and made the localization call and it works fine

OK, I figured this out .. I am getting the .resx file because it is truly embedded into the main assembly. The other files are getting built into separate dlls for each language, I then need to copy them into the same folder that I build my aggregate container from, my resource manager then sees all languages.

Related

Access Resources from Externally-Created .resx File

My main Windows Forms (managed C++) project has a class that presents an image with tiles that can be shown or hidden to create a responsive diagram.
I created a separate utility app that helps me get all the images positioned correctly, etc. This app is written in C# and writes a .resx file containing the image data and positioning, using the following code snippet:
using(ResXResourceWriter resx = new ResXResourceWriter(sfd.FileName)) {
resx.AddResource("Size", canvas.Size);
List<int> IDs = canvas.IDs;
resx.AddResource("IDList", IDs);
resx.AddResource("BackgroundIndex", canvas.BackgroundIndex);
foreach(int id in IDs) {
String positionKey = String.Format("Position.id{0}", id);
String visibilityKey = String.Format("Visibility.id{0}", id);
String imageKey = String.Format("Image.id{0}", id);
resx.AddResource(imageKey, canvas.TileImage(id));
resx.AddResource(positionKey, canvas.TilePosition(id));
resx.AddResource(visibilityKey, canvas.TileVisible(id));
}
}
I can open the .resx file in a text editor and see that it is well-formed and contains the expected data.
Then I take that .resx file and add it to my main application's project. Now I can't figure out how to get at the resources inside it. The code I've tried is:
ResourceManager ^ image_rm = gcnew ResourceManager(
"resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
At runtime, the second line (the GetResourceSet call) throws a System.Resources.MissingManifestResourceException with the following message text:
Resource load failure:
Could not find any resources appropriate for the specified culture or the
neutral culture. Make sure "resx_file_name_without_extension.resources" was
correctly embedded or linked into assembly "my_assembly" at compile time, or
that all the satellite assemblies required are loadable and fully signed.
I suspect my problem is...well I don't really know. Maybe I'm not using the right identifier in the ResourceManager constructor. I tried explicitly setting "Excluded From Build: No" and "Content: Yes" in the file's properties, but that had no effect.
Is it even possible to drop an externally-created .resx file into a project and get at the resources within? I definitely need it compiled in; I can't ship a product with dangling .resx files. I can always create a set of static data objects in .cpp files, but the .resx approach seemed more elegant...
Turns out a comment on this unanswered question was the secret sauce. Prepending the root namespace to the identifier made the ResourceManager happy:
ResourceManager ^ image_rm = gcnew ResourceManager(
"my_root_namespace.resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
Just how or why the compiler decided to place the resources within that namespace is still a bit of a mystery to me, but that's trivia for another day.
The question to which I link involves a .resx created with VS within the project, and mine involves adding one created externally, so I think it's a different-enough situation to warrant a separate Q/A.

ASP.NET Resource File, Resource Manager for Language Translation

Spending hours on this. Thinking my thought process might be off..
I wanted to create one point of entry for language translation across different libraries and applications.
What I did was the following:
Created New Class Library Project called Translations
At Root Level Added New Item - MyStrings.en-US.resx file
Populated resx file
resx - Access Modifier set to Public
At Root Level of Translations Project Added New Item Class - Translator
Added Property
public class Translator
{
private ResourceManager _translationManager;
public ResourceManager TranslationManager
{
get
{
if (_translationManager == null)
{
_translationManager = new ResourceManager("MyStrings", this.GetType().Assembly);
}
return _translationManager;
}
}
}
In WebSite (not web project but website) Added Reference to Translations Project
In the code behind declared
private Translator _translate;
public Translator Translate
{
get
{
if (_translate == null)
{
_translate = new Translator();
}
return _translate;
}
}
then in a LINQ statement
Title = TranslationManager.GetString(appsAvailable.Value.ResourceKey, CurrentCulture)
ResourceKey does have a value
CurrentCulture = en-US
And I am getting this error
Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure "MyStrings.resources" was correctly
embedded or linked into assembly "Translations" at compile time, or
that all the satellite assemblies required are loadable and fully
signed.
When I look at my bin/obj/debug folder I am seeing this Translations.MyStrings.en-US.resources
which is not the name it is looking for. I have tried to modify the "basename" for the manager from "MyStrings" to 'Translations.MyStrings" but I get a similar error stating "Translations.MyStrings.resources" can't be found. I have also tried just saying okay forget the culture right now let's access it "Translations.MyStrings.en-US" as the base name. and it says it still can not find it.
Any ideas of where I am going wrong? I am thinking it needs to be copied somewhere so the software finds it but don't know where it goes? Or am I trying to do something that it is not meant to do?
Your help is greatly appreciated!
Just download MAT (Multilingual App Toolkit) for Visual Studio. https://marketplace.visualstudio.com/items?itemName=MultilingualAppToolkit.MultilingualAppToolkit-18308
This is the way to go to translate and maintain your projects in Visual Studio ;-)
https://blogs.msdn.microsoft.com/matdev/

Using Resource files for things other than language

I am working on an MVC application that is effectively a piece of middleware to provide admin and reporting on an external BPM solution.
The users of the system aren't all for the same business function and may refer to fields as different things (e.g. division A calls a client a Client but division B calls them a Prospect). Is there a way I could have resource files for
Resources.divA.resx
Resources.divB.resx
Resources.divC.resx
From my googling, it appears it can only be used for localization.
You can use the ResourceManager class to help with this.
When you add some resources to a project, the IDE automatically adds a Resources.Designer.cs file to the project to manage the resources. The generated code looks something like this:
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AssemblyName.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
This uses the ResourceManager constructor that looks up resources based on a combination of a root name and the current locale.
You can write similar code yourself, but compute a root name based on whether the the resources are for division A, B or C. So you would call it something like "AssemblyName.Resources.divA" instead of "AssemblyName.Properties.Resources".
You can then also have specific versions for each other supported language and they will be automatically loaded (if present) for the current culture. This is how it works for the IDE-managed resources.

Get relative path of XML File located in another project but Same Solution

I have found many Articles and Questions about finding an XML file but all of them are for Same Project.
Suppose I have my Project structure as shown below:
ABC <------ Solution
|--ABC.Data <------ Project
| |--XMLFiles <-------Folder
| |--AA.xml
|
|--ABC.Client <------ Project
| |--ViewModels <-------Folder
| |-MainViewModel.cs
Now I would like to load AA.xml file in MainViewModel.cs using XDocument.Load(....path.....).
So, how can I get path?
You will have to move back from the executing assembly folder on parent of ABC.Data and ABC.Client. For example the executing assembly is located in ABC.Client->ViewModels->Bin->Debug
XDocument.Load("../../../../../ABC.Data/ABC.Data/AA.xml");
But practically I see no use of it as the project hierarchy wont be there when you deploy the application. If you have XML file that need to be accessed by multiple assemblies the simply put that xml file in Execution folder. All the assemblies will be able to access it.
You can also make a separate assembly that exposes the AA.xml file data for read and write for all other projects by adding reference of that assembly to those projects. I would prefer this method.
you need a couple of settings to make your scenario work
first right click the xml file(or any file you want to access) and set 'Copy to Output Directory' to 'Copy Always' and when you build or publish the folder structure of that file(AA.xml in your case) will be created on bin or publish(web project) folder and you have simply have to write this code
var path = HostingEnvironment.ApplicationPhysicalPath+"\\bin";//path to you bin
if you are using winforms
var path = Application.StartupPath;//path to you bin
finally
var fullpath=path+"\\XMLFiles\\AA.xml";
XDocument.Load(fullpath) ;
however the better approach will be to create a Helper Class that will fetch the xml content for you application such as
public static class XMLHelpers
{
public static XMLDocument GetXML(string KEY)
{
string file="";
switch(KEY)
{
case "AA": file=Path.Combine(file,"AA.txt");
break;
}
var xmldoc=new XMLDocument();
xmldoc.Load(file);
return xmldoc;
}
}

Get Assembly name at compile time in Visual Studio

Is there a way to find out the assembly name at design-time (i.e. not using reflection or runtime APIs such as System.Reflection.Assembly.GetEntryAssembly) from within Visual Studio?
The scenario requires a tool to get the assembly name that a Visual Studio project will eventually compile into.
This is like parsing the AssemblyName property of the .csproj - I am wondering if there are any APIs that can give this information reliably.
Please do not respond back with runtime APIs that use reflection - there is no assembly file present at the time I need the assembly name - just the metadata of the assembly in the csproj file.
if you are calling the tool via a post/pre-build event, this data is very easy to access.
Just go to the "project properties->Build Events" tab, then select either "edit pre-build" or "edit post-build", depending on when you want the tool to run. This should bring up an edit window with the ever helpful "Macros >>" button. Press this and you will be given a heap of macros to use and should be pretty much everything you need.
The "API" you could use is LINQ to XML after all the .csproj file is just xml. (and you can get the location of the .csproj file if you need from the solution file which for some reason is not XML but can be easily parsed)
You can use "TargetName" available in Macros for Post-build events. It will give you the assembly name for your project.
After a quick run through MSDN I found this article which might be a good start for some further research:
Accessing Project Type Specific Project, Project Item, and Configuration Properties
I think you will need to write some regular expression that will give you the value of "AssemblyTitle" attribute in AssemblyInfo.cs file.
Something like this:
public class Assembly
{
public static string GetTitle (string fileFullName) {
var contents = File.ReadAllText (fileFullName); //may raise exception if file doesn't exist
//regex string is: AssemblyTitle\x20*\(\x20*"(?<Title>.*)"\x20*\)
//loading from settings because it is annoying to type it in editor
var reg = new Regex (Settings.Default.Expression);
var match = reg.Match (contents);
var titleGroup = match.Groups["Title"];
return (match.Success && titleGroup.Success) ? titleGroup.Value : String.Empty;
}
}

Categories

Resources