C# - Cannot getting a string from ResourceManager (from satellite assembly)

35,331

Solution 1

I found why, hope this will help someone that is in the same case.

So, I looked in MyApp_FR.dll the code generated to use the Resource file, it is :

new global::System.Resources.ResourceManager("MyApp_FR.Properties.Resources", typeof(Resources).Assembly);

but when retrieving the manifest file names, I got :

"MyApp_FR.Properties.Resources.resources"

Seems to be there is a .resource to much in this room... By removing it, I can use my ResourceManager normally, all works fine...

Final code :

Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)
{
    string manifest = manifests[0].Replace(".resources", string.Empty);
    manager = new ResourceManager(manifest, resourceAssembly);
}

// Works !
manager.GetString("PleaseCallIT", null);

Solution 2

From Microsoft Support:

This problem occurs if you use a localized resource that exists in a satellite assembly that you created by using a .resources file that has an inappropriate file name. This problem typically occurs if you manually create a satellite assembly:

Try this KB:

http://support.microsoft.com/kb/839861

Solution 3

An alternate approach, put in the following as test code:

string[] resources = 
    System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();

In debugging, check the contents of resources to see if it matches what you are loading with ResourceManager.

Especially note, if you get something like 'MyAssembly..Resources.resources', then you will need to explicitly add 'Resources' to the ResourceManager constructor:

    private static readonly ResourceManager stringTable =
 new ResourceManager("MyAssembly.Resources", Assembly.GetExecutingAssembly());
Share:
35,331
Arnaud F.
Author by

Arnaud F.

(c) Feel good Inc.

Updated on July 09, 2022

Comments

  • Arnaud F.
    Arnaud F. almost 2 years

    I'm developing a localisable application. In my "local" resource file, I've the language used by default (english) and if possible, I load the user's preference and culture and load strings translated in is language.

    So what I've done :

    private static CultureInfo _culture = CultureInfo.CurrentUICulture;
    private static ResourceManager _manager;
    
    private static void ToNeutralCulture()
    {
        while (!_culture.IsNeutralCulture)
        {
            _culture = _culture.Parent;
        }
    }
    
    private static void LoadCulture()
    {
        ResourceManager manager = Properties.Resources.ResourceManager;
    
        try
        {
            ToNeutralCulture();
    
            string assembly = Assembly.GetCallingAssembly().GetName().CodeBase;
            string assemblyDir = Path.GetDirectoryName(assembly);
            string assemblyName = Path.GetFileNameWithoutExtension(assembly);
            string resourceFileName = string.Format(CultureInfo.InvariantCulture,
                @"{0}\{1}_{2}.dll",
                assemblyDir,
                assemblyName,
                _culture.Name.ToUpper());
    
            FileInfo resourceFile = new FileInfo(resourceFileName);
            if (resourceFile.Exists)
            {
                Assembly resourceAssembly = Assembly.LoadFrom(resourceFile.FullName);
                string[] manifests = resourceAssembly.GetManifestResourceNames();
    
                if (manifests.Length == 1)
                {
                    manager = new ResourceManager(manifests[0], resourceAssembly);
                }
    
                using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
                {
                    IDictionaryEnumerator dict = reader.GetEnumerator();
                    while (dict.MoveNext())
                    {
                        string key = dict.Key as string;
                        object val = dict.Value;
    
                        //string mVal = manager.GetString(key);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine(ex.Message);
    
            Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,
                "Fail to loading culture {0}", 
                (_culture == null) ? "--" : _culture.EnglishName));
        }
    
        _manager = manager;
    }
    

    Assembly is correctly loaded and the enumerator will display me all resources present in the resource file, well, works fine except :

    string mVal = manager.GetString(key);
    

    When I uncommented this line, I've an System.Resources.MissingManifestResourceException, can someone tell me why?

    Thanks !


    [EDIT]

    Project "MyApp"

    namespace MyApp
    {
        Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
        string[] manifests = resourceAssembly.GetManifestResourceNames();
    
        if (manifests.Length == 1)
        {
            manager = new ResourceManager(manifests[0], resourceAssembly);
        }
    
        // Throws the exception
        manager.GetString("PleaseCallIT", null);
    
        // Works
        using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
        {
            IDictionaryEnumerator dict = reader.GetEnumerator();
            while (dict.MoveNext())
            {
                string key = dict.key as string; // PleaseCallIT
                object val = dict.value; // Please call IT.
            }
        }
    }
    

    Project "MyApp_FR" (Resources.Designer.cs auto-generated file)

    namespace MyApp.Properties {
        // ...
        internal static string PleaseCallIT {
            get {
                return ResourceManager.GetString("PleaseCallIT", resourceCulture);
            }
        }
    }
    

    I don't understand...