136

Is there a way to loop through all the resources in a .resx file in C#?

Ilya
  • 21,871
  • 8
  • 73
  • 92
np.
  • 2,319
  • 4
  • 31
  • 36
  • 2
    Can you elaborate on whether the RESX file is internal to your project or whether you want (or need to) read a separate RESX file or read RESX from another assembly? – Abel Jan 11 '10 at 10:18

11 Answers11

259

You should always use the resource manager and not read files directly to ensure globalization is taken into account.

using System.Collections;
using System.Globalization;
using System.Resources;

...

/* Reference to your resources class -- may be named differently in your case */
ResourceManager MyResourceClass =
    new ResourceManager(typeof(Resources));

ResourceSet resourceSet =
    MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
    string resourceKey = entry.Key.ToString();
    object resource = entry.Value;
}
wonea
  • 4,783
  • 17
  • 86
  • 139
Oundless
  • 5,425
  • 4
  • 31
  • 33
  • 12
    It took me a little to figure out that you need this line to declare MyResourceClass. `ResourceManager MyResourceClass = new ResourceManager("Resources.ResourceFileName", System.Reflection.Assembly.Load("App_GlobalResources"));` – JoeFletch Sep 20 '12 at 02:11
  • 6
    @JoeFletch: it doesnt need this line. The code calls the Resource File directly. Example: i have a file named PageList.resx, then i'll call: ResourceSet resourceSet = PageList.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true); – Gabriel Feb 06 '13 at 11:23
  • @Gabriel, thanks for the update! I will have to go back to my code to check this out. – JoeFletch Feb 06 '13 at 13:25
  • 3
    JoeFletch's line actually helped me out. I had a resx in located in another C# project, so his line allowed me to call that dll assembly and load in the resources that way. Also, when I tried to include the PageList on my code, it threw an error for PageList.ResourceManager.. saying "PageList does not contain a definition for ResourceManager". And finally, string resourceKey = entry.Key threw an error, I used instead "object resourceKey = entry.Key" – sksallaj Aug 06 '13 at 15:34
  • 2
    Depending if you actually have cultures defined in your resource, you will have to switch to CultureInfo.InvariantCulture. Here I was using resources in a library, not a WinForms app. – Israel Lopez Nov 15 '14 at 18:31
  • For those using this inside a library, and added .resx file named "Resources" to the project, replace `MyResourceClass` with `Properties.Resources`. – Eido95 Aug 15 '16 at 17:11
27

Blogged about it on my blog :) Short version is, to find the full names of the resources(unless you already know them):

var assembly = Assembly.GetExecutingAssembly();

foreach (var resourceName in assembly.GetManifestResourceNames())
    System.Console.WriteLine(resourceName);

To use all of them for something:

foreach (var resourceName in assembly.GetManifestResourceNames())
{
    using(var stream = assembly.GetManifestResourceStream(resourceName))
    {
        // Do something with stream
    }
}

To use resources in other assemblies than the executing one, you'd just get a different assembly object by using some of the other static methods of the Assembly class. Hope it helps :)

Svish
  • 152,914
  • 173
  • 462
  • 620
  • Can you enumerate resources *not* located in a folder called 'Resource'? I'd like to enumerate all resource images located in my project in a folder called 'Images'. – Simon Bosley Apr 27 '16 at 08:23
  • Pretty sure it doesn't care about where it's located? Test it? – Svish Apr 30 '16 at 20:07
  • 1
    I had files in a folder for inporting sql files and this worked perfectly. I added a conversion from a stream to string so I could read the file and had no issues. – ErocM Aug 23 '16 at 18:16
11

Use ResXResourceReader Class

ResXResourceReader rsxr = new ResXResourceReader("your resource file path");

// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
    Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}
rahul
  • 184,426
  • 49
  • 232
  • 263
7
  // Create a ResXResourceReader for the file items.resx.
  ResXResourceReader rsxr = new ResXResourceReader("items.resx");

  // Create an IDictionaryEnumerator to iterate through the resources.
  IDictionaryEnumerator id = rsxr.GetEnumerator();       

  // Iterate through the resources and display the contents to the console.
  foreach (DictionaryEntry d in rsxr) 
  {
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
  }

 //Close the reader.
 rsxr.Close();

see link: microsoft example

koopajah
  • 23,792
  • 9
  • 78
  • 104
logicfalse
  • 79
  • 1
  • 1
  • 4
    Note that this class is in the `System.Windows.Forms` assembly and is not automatically added if you're using an MVC app – Rob Scott Aug 22 '16 at 17:18
7

The minute you add a resource .RESX file to your project, Visual Studio will create a Designer.cs with the same name, creating a a class for you with all the items of the resource as static properties. You can see all the names of the resource when you type the dot in the editor after you type the name of the resource file.

Alternatively, you can use reflection to loop through these names.

Type resourceType = Type.GetType("AssemblyName.Resource1");
PropertyInfo[] resourceProps = resourceType.GetProperties(
    BindingFlags.NonPublic | 
    BindingFlags.Static | 
    BindingFlags.GetProperty);

foreach (PropertyInfo info in resourceProps)
{
    string name = info.Name;
    object value = info.GetValue(null, null);  // object can be an image, a string whatever
    // do something with name and value
}

This method is obviously only usable when the RESX file is in scope of the current assembly or project. Otherwise, use the method provided by "pulse".

The advantage of this method is that you call the actual properties that have been provided for you, taking into account any localization if you wish. However, it is rather redundant, as normally you should use the type safe direct method of calling the properties of your resources.

Abel
  • 56,041
  • 24
  • 146
  • 247
  • 2
    Why use reflection when there is a ResourceSet available? – Oundless Jan 11 '10 at 10:12
  • That's what I'd wonder as well (see last paragraph). Just wanted to show an alternative method, but more importantly, wanted to show that the class is made fully accessible and you don't need to do any magic by hand (the first paragraph). – Abel Jan 11 '10 at 10:14
2

You can use ResourceManager.GetResourceSet.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
2

If you want to use LINQ, use resourceSet.OfType<DictionaryEntry>(). Using LINQ allows you, for example, to select resources based on their index (int) instead of key (string):

ResourceSet resourceSet = Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (var entry in resourceSet.OfType<DictionaryEntry>().Select((item, i) => new { Index = i, Key = item.Key, Value = item.Value }))
{
    Console.WriteLine(@"[{0}] {1}", entry.Index, entry.Key);
}
Ron Inbar
  • 2,044
  • 1
  • 16
  • 26
1

With the nuget package System.Resources.ResourceManager (v4.3.0) the ResourceSet and ResourceManager.GetResourceSet are not available.

Using the ResourceReader, as this post suggest: "C# - Cannot getting a string from ResourceManager (from satellite assembly)"

It's still possible to read the key/values of the resource file.

System.Reflection.Assembly resourceAssembly = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName("YourAssemblyName"));
String[] manifests = resourceAssembly.GetManifestResourceNames(); 
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
   System.Collections.IDictionaryEnumerator dict = reader.GetEnumerator();
   while (dict.MoveNext())
   {
      String key = dict.Key as String;
      String value = dict.Value as String;
   }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Jordy
  • 176
  • 4
1

Simple read loop use this code

var resx = ResourcesName.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, false, false);

foreach (DictionaryEntry dictionaryEntry in resx)
{
    Console.WriteLine("Key: " + dictionaryEntry.Key);
    Console.WriteLine("Val: " + dictionaryEntry.Value);
}
azhe403
  • 377
  • 2
  • 3
0

Using LINQ to SQL:

XDocument
        .Load(resxFileName)
        .Descendants()
        .Where(_ => _.Name == "data")
        .Select(_ => $"{ _.Attributes().First(a => a.Name == "name").Value} - {_.Value}");
Andriy Tolstoy
  • 5,690
  • 2
  • 31
  • 30
0

I put my PDF into the resources folder for an MVC 5 Razor project. This is how I opened the file:

    public IActionResult ViewCCACH()
    {
        return GetDocumentLikeThis("FORM CC");
    }

    private IActionResult GetDocumentLikeThis(string likeThis)
    {
        ResourceManager MyResourceClass = new ResourceManager(typeof(Resources));

        ResourceSet resourceSet = MyResourceClass.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
        //ResourceManager resourceSet = new ResourceManager("ACH AUTH FORM CC Blank.pdf", System.Reflection.Assembly.Load("App_GlobalResources"));
        foreach (DictionaryEntry entry in resourceSet)
        {
            string resourceKey = entry.Key.ToString();
            object resource = entry.Value;
            if (resourceKey.Contains(likeThis))
            {
                string RunningPath = AppDomain.CurrentDomain.BaseDirectory;
                string FileName = string.Format("{0}Properties\\" + resourceKey + ".pdf", Path.GetFullPath(Path.Combine(RunningPath, @"..\..\..\")));

                var fileStream2 = new FileStream(FileName, FileMode.Open, FileAccess.Read);
                var fsResult2 = new FileStreamResult(fileStream2, "application/pdf");
                return fsResult2;

            }

        }


        return View();
    }

The code in .cshtml was simple:

<a class="tablinks btn btn-primary m-2 pull-right" href="/Merchant/ViewCCACH" target="_blank">Download File</a>