C# - Fastest way to get resource string from assembly - c#

I really don't know/have the answer, knowledge to find a resource value using a key from a resx file in a assembly using c#.(or may be i am ignorant).
What would be the fastest code, way i can retrieve string values or values using a key from a resource file which is embedded as resource in a assembly. I am storing friendly messages for exceptions in the resource file and would like to use them when required.
Does a static class exist for this purpose?
Are there open source mature projects i can use for this?

If the resource is in the same assembly as the code, then the following will do:
String resourceValue = MyAssemblyNameSpace.Properties.Resources.ResourceName
Taken from this SO answer.

Assembly assembly = this.GetType().Assembly;
ResourceManager resourceManager = new ResourceManager("Resources.Strings", assembly);
string myString = resourceManager.GetString("value");

string val = Resources.ResourceManager.GetString("resource_name");
Given "resource_name" you can retrieve resource value.

you can use ResourceManger to get the string value from Assembly
Get Resource from Assembly
ResourceManager ResManager= new ResourceManager("yourResource",
Assembly.GetExecutingAssembly());
String strResourveValue = ResManager.GetString("YourStringKey");

var thread = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
var culture = new CultureInfo(thread);
var resourceManager = new ResourceManager(typeof(Resources.Resource));
string value = resourceManager.GetString(name, culture);

When I made a new project for my unit tests of type C# class library called UnitTests, I right clicked and Added a new Resource. I named that UnitTestsResources. I added 2 strings to that resource. I was then able to conveniently able to access them like this
UnitTestsResources.NoDeviceRequireMsg
I was curious how that worked so i pulled up the code behind the resource file and it makes sense. Visual Studio made a internal class with static accessors.. It looks like this for me
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class UnitTestsResources {
//Some auto generated code
/// <summary>
/// Looks up a localized string similar to OPOS Device is required for test.
/// </summary>
internal static string DeviceRequireMsg {
get {
return ResourceManager.GetString("DeviceRequireMsg", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OPOS Device must not be installed for test.
/// </summary>
internal static string NoDeviceRequireMsg {
get {
return ResourceManager.GetString("NoDeviceRequireMsg", resourceCulture);
}
}
}
Since it is only for my unit tests I am content with this. Hope it helps someone else.

To improve on Herzbube's answer I will show how I implemented this...
Rather than creating projects or folders for the resource file, just right click your project and do add -> new item, then choose resources file. Open the resources file stick in your strings, save as a useful name, and navigate over to C# where you want to use them, then it is just:
String resourceValue = MyProjectName.MyResourceFileName.MyResourceRowItem;
If that isnt working pay attention to the access modifier drop down when inside your resx file.

Related

Roslyn AdditionalFiles

I want to develop a Roslyn Code Analyzer which has access to some static configuration in the form of text files. Since an analyzer cannot access the local file system I guess the only way to read such external configuration is via Context Option and AdditionalFiles.
I am aware of this example dealing with this problem:
https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Using%20Additional%20Files.md
What the example does not say is: Is the analyzer reading the AdditionalFiles shipped with the analyzer assembly or the target being analyzed? The latter does not solve my problem because the configuration is analyzer and not target specific.
Update:
I cannot use the standard "Add New Text File" resource mechanism either. The according context menu entry is disabled:
This seems to be related to the TargetFrameworkProfile which is set to Profile7 when creating a new "Analyzer with Code Fix (NuGet + VSIX)" project.
You should be able to use this overload of the ResourceManager class and just pass in a type defined in your assembly.
class MyResourceManager
{
private readonly ResourceManager _manager;
public MyResourceManager()
{
_manager = new ResourceManager(typeof(MyResourceManager))
}
public string GetStringResouce(string name)
{
return _manager.GetString(name);
}
}

Class Library Localization in Windows Universal / Store App

I have a solution with a Windows Store app project and a Class Library project and I want to add Localization support.
How can I add the all the Resource files to my Class Library and use them in both my App and Class Library?
In order to avoid writing a lot of boilerplate and error prone code when you add a new resource string like:
Add it to .resw file
Add it to your Static class that provides access to the resource
Add it to each language specific .resw file (ex: en, fr, pt, etc)
You can use the following approach:
Create "Strings" folder and add there just one folder for default language (for example "en-US") in your Class Library
Add Resources.resw file to "en-US" folder with required keys/values
Install Multilingual App Toolkit
Enable MAT in VS for your Class Library (VS->Tools->Enable Multilingual App Toolkit)
Add required languages to your Class Library (VS->Project->Add Translation languages...)
Install ResW File Code Generator VS extension
Go to Resources.resw file properties and set Custom Tool to "ReswFileCodeGenerator" (you can also specify namespace in Custom Tool Namespace)
To solve issue with supported languages detection(currently generated manifest contains supported languages according to folder structure "Strings/en-US") you need to add folders for all required languages in your App library ("fr-FR", "bg-BG", etc) and put Resources.resw file with only one fake key.
Build your solution and enjoy!
With this approach all your resources are available via static class generated by ReswFileCodeGenerator and all of them work with x:uid in XAML. You don't need to care about keys synchronization between different languages. Also MAT can translate your resources for you.
Ok, I found how to do this and with a sample project found here
Basically the implementation is the following:
In the ClassLibrary create a folder named "Strings"
Inside the Strings folder create one for each language (ex: en, fr, pt, etc)
And add a Resources.resw in each of those folders with your keys/values
Now add a new Class in your ClassLibrary that has the following code(adapted to your project):
using System;
using Windows.ApplicationModel.Resources;
namespace MyClassLibraryName.Tools {
public static class LocalizationTool {
static ResourceLoader resourceLoader = null;
public static string MyStringOne {
get {
String name;
GetLibraryName("MyStringOne", out name);
return name;
}
}
private static void GetLibraryName(string resourceName, out string resourceValue) {
if(resourceLoader == null) {
resourceLoader = ResourceLoader.GetForCurrentView("MyClassLibraryName/Resources");
}
resourceValue = resourceLoader.GetString(resourceName);
}
}
}
And in your ClassLibrary or MainApp just call the following:
string text = LocalizationTool.MyStringOne;

Could not find any resources appropriate for the specified culture or the neutral culture

I have created an assembly and later renamed it.
Then I started getting runtime errors when calling:
toolsMenuName = resourceManager.GetString(resourceName);
The resourceName variable is "enTools" at runtime.
Could not find any resources
appropriate for the specified culture
or the neutral culture. Make sure
"Jfc.TFSAddIn.CommandBar.resources"
was correctly embedded or linked into
assembly "Jfc.TFSAddIn" at compile
time, or that all the satellite
assemblies required are loadable and
fully signed.
The code:
string resourceName;
ResourceManager resourceManager = new ResourceManager("Jfc.TFSAddIn.CommandBar", Assembly.GetExecutingAssembly());
CultureInfo cultureInfo = new CultureInfo(_applicationObject.LocaleID);
if(cultureInfo.TwoLetterISOLanguageName == "zh")
{
CultureInfo parentCultureInfo = cultureInfo.Parent;
resourceName = String.Concat(parentCultureInfo.Name, "Tools");
}
else
{
resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Tools");
}
toolsMenuName = resourceManager.GetString(resourceName); // EXCEPTION IS HERE
I can see the file CommandBar.resx included in the project, I can open it and can see the "enTools" string there. It seems that either resources are not included into assembly or resource are included but .NET cannot resolve the name.
I think simpler solution would be to create separate resources file for each language.
As far as this case is concerned check if the assembly containing resources has the default namespace set to the same text (Project->Properties->Default namespace; in VS)
Check as well if the resx file has a property BuildAction set to "Embedded resource"
Sounds similar to an issue we had. The namespace was incorrect in the resource file's designer. I fixed it by manually re-running the custom-tool on the resx file.
Right click your.resx, and click Run Custom Tool.
I'm sure you've already got the answer, but just in case:
You can view your ManifestResourceName by calling
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames()
Check that Manifest name and your name in GetString() calling are identical.
Also, be sure you have correct namespace in designer.resx file:
namespace Jfc.TFSAddIn {
...
global::System.Resources.ResourceManager temp =
new global::System.Resources.ResourceManager(
"Jfc.TFSAddIn.CommandBar", typeof(CommandBar).Assembly);
...
}
Open resx file properties: "Build Action" should be "Embedded Resource"
For me, the source of the problem was naming the rex files starting with a number:
20160216_tranlation.resx
I had to add an underscore _ before the resx file name when calling GetGlobalResourceObject:
public static string getResource(string key)
{
return HttpContext.GetGlobalResourceObject("_20160216_tranlation", key).ToString();
}
I corrected the namespace in designer file (Resources.Designer.cs) in ResourceManager static property & it worked for me.
See the code below:
[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("XYZAssembly.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
I added a temporary class within my Form.cs while (testing || debugging) that caused this exception to be thrown. The Form.resx file (Name || Resource ID) was modified to the temporary class name instead of the Form class name. This caused the issue for me. I (corrected || alleviated) this by creating a separate file for my temporary class in the project.
One Solution is to change the property of resx file from content to Embedded Resource and Build it.Sure this time u vil get
I have encountered this issue in Xamarin.Forms, when I tried to the rename the project, the resources could not be loaded anymore with the same stated error text.
To fix the problem I had to modify the .csproj by a text editor, and change the logical name of the embedded resource.
<EmbeddedResource Include="Localization\TextResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>TextResources.Designer.cs</LastGenOutput>
<LogicalName>YourNewNamespaceName.TextResources.resources</LogicalName>
<SubType>Designer</SubType>
</EmbeddedResource>
Also watch out for the autogenerated class when you rebuild it, the namespace stated in there might change.
Hope it helps someone that went into the same situation.
Got this error when I added a class ABOVE the partial form class in my Windows forms app.
It went away when I moved the class BELOW the partial form class.
This answer solved the problem for me! GetGlobalResourceObject

.Net Reflector not properly linking resources

Ive decompiled a library but when i try to run it, anything that requests something from the resource manager doesnt work properly leaving me with "{"Could not find any resources appropriate for the specified culture or the neutral culture. Make sure \"Logistics.Products.LayerPicking.Properties.Resources.resources\" was correctly embedded or linked into assembly \"LayerPicking.PBG\" at compile time, or that all the satellite assemblies required are loadable and fully signed."}"
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager
{
get
{
if (resourceMan== null)
{
System.Resources.ResourceManager manager = new System.Resources.ResourceManager("Logistics.Products.LayerPicking.Properties.Resources", typeof(Resources).Assembly);
resourceMan = manager;
}
return resourceMan;
}
}
It looks like the decompiling changed the name. The Resource looks like it is LayerPicking.PBG.KUKARoboter.Logistics.Products.LayerPicking.Properties.Resources - notice the "LayerPicking.PBG." - which is the name of your project.
VS.Net likes to add the default namespace of the project to the beginning of the resources when it embeds them.
So here are 2 options (you can do either one - I would recommend #1):
Change your default namespace to KUKARoboter and rename your resx files to start with Logistics (not KUKARoboter).
Search for the "KUKARoboter.Logistics string and add in your default namespace to the string so it reads like the string it is looking for "LayerPicking.PBG.KUKARoboter.Logistics"

Get executing assembly name from referenced DLL in C#

What is the best way to get the application name (i.e MyApplication.exe) of the executing assembly from a referenced class library in C#?
I need to open the application's app.config to retrieve some appSettings variables for the referenced DLL.
To get the answer to the question title:
// Full-name, e.g. MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
string exeAssembly = Assembly.GetEntryAssembly().FullName;
// or just the "assembly name" part (e.g. "MyApplication")
string exeAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
As mentioned by #Ben, since you mention wanting to get the configuration information, use the ConfigurationManager class.
If you want to get the current appdomain's config file, then all you need to do is:
ConfigurationManager.AppSettings....
(this requires a reference to System.Configuration of course).
To answer your question, you can do it as Ray said (or use Assembly.GetExecutingAssembly().FullName) but I think the problem is easier solved using ConfigurationManager.
To get the exact name without versions, etc. use:
string appName = Assembly.GetEntryAssembly().GetName().Name;
Works with .NET v1.1 and later.
You can get the assembly through the class type...
typeof(MyClass).Assembly
If you want the name of the parent EXE and not the referenced DLL assembly - you will need to use this:
Assembly.GetEntryAssembly().GetName().Name
This will return the EXE name (minus the .EXE part).
Using GetExecutingAssembly() is not right as per the OP's question (first paragraph of it!) as it will return the DLL name.
You should never couple your libraries to a consumer (in this case Web, WinForm or WCF app). If your library needs configuration settings, then GIVE it to the library.
Don't code the library to pull that data from a consumer's config file. Provide overloaded constructors for this (that's what they are for).
If you've ever looked at the ConfigurationManager.AppSettings object, it is simply a NameValueCollection. So create a constructor in your library to accept a NameValueCollection and have your consumer GIVE that data to the library.
//Library
public class MyComponent
{
//Constructor
public MyComponent(NameValueCollection settings)
{
//do something with your settings now, like assign to a local collection
}
}
//Consumer
class Program
{
static void Main(string[] args)
{
MyComponent component = new MyComponent(ConfigurationManager.AppSettings);
}
}
If you want to read (and display) version number:
Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
AssemblyName assname = ass.GetName();
Version ver=assname.Version;
Somewhere in application (ie Title block in a Windows form)
this.Text = "Your title Version " + ver;
For the short name of an assembly from a class instance:
Me.GetType ().Assembly.GetName().Name

Categories