.Net Reflector not properly linking resources - c#

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"

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);
}
}

Get assembly name at compile time and use it in code [duplicate]

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;
}
}

Different resource files for different client deployments

I'm developing a WinForms application for 2 clients. The difference between the clients are only in branding: ClientA gets LogoA.png. ClientB gets LogoB.png. I need to ship the application to them as in installer and as zip file with all executables.
I'm thinking putting the images in different resource files and compile them as satellite assemblies and on the build server, when I produce zip-file and installer, I include only ResourceA for ClientA and ResourceB for ClientB. That is the plan, but I've never done this before.
The documentation says that resource files should be identified by language and culture codes. Both of my clients will run their machines in English (en-GB or en-US). I can ignore the recommendation and call the resources by the name of clients. But would they be picked up by the application? (taking there is only one resource file and machine culture does not match the resource culture code).
Is there a better solution for that?
p.s. I know about compiler directives, but it is making code hacky and dirty. Possibly, in the future, clients will have different text on the screens and that is the perfect case for the resources.
You can create a separate build configuration for each company. Then you can change the .csproj file to have msbuild tasks which will replace default resource file with chosen company resources, here is example how to check current configuration in msbuild.
<PropertyGroup Condition="'$(Configuration)' == 'CompanyABuild'">
//set resource to point to company A
</PropertGroup>
<PropertyGroup Condition="'$(Configuration)' == 'CompanyBBuild'">
//set resource to point to company B
</PropertGroup>
You can add to separate resource file one for clientA another one for clientB (ClientA.resx, Clinetb.resx). Then add a config entry in your app.config file with the name of the resource to use.
Then you need to create a wrapper class which will provide you resources depending on the config value, you need to use dynamic objects and resource managers here is a sample code:
class Program
{
static void Main(string[] args)
{
var res = new CompanyAResource();
var companyResources = new global::System.Resources.ResourceManager("ConsoleApplication1.CompanyAResource", typeof(CompanyAResource).Assembly);
dynamic resources = new DynamicResources(companyResources);
string name = resources.CompanyName;
Console.WriteLine(name);
}
}
public class DynamicResources : System.Dynamic.DynamicObject
{
private ResourceManager resources;
public DynamicResources(ResourceManager resources)
{
this.resources = resources;
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
{
result = this.resources.GetString(binder.Name);
return true;
}
}

C# - Fastest way to get resource string from assembly

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.

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

Categories