16

I have a resource assembly with image files in it that are built using Resource or Content build action. This makes these files accessible using the Uris. However I cannot find the way to enumerate such resources.
If I set the build action to Embedded Resource it becomes possible to enumerate the files with the following code:

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

but it in turn makes these files inaccessible using Uris.

The question is - how to enumerate resources that are compiled with either Resource or Content build action?

NOTE: As Thomas Levesque pointed out it is possible to enumerate such resources by leveraging the AssemblyAssociatedContentFileAttribute, but it seems to only work for WPF Application assemblies and not for class library ones. So the question is still open.

Alex_P
  • 1,886
  • 1
  • 19
  • 22

1 Answers1

33

You can enumerate the AssemblyAssociatedContentFile attributes defined on the assembly :

var resourceUris = Assembly.GetEntryAssembly()
                   .GetCustomAttributes(typeof(AssemblyAssociatedContentFileAttribute), true)
                   .Cast<AssemblyAssociatedContentFileAttribute>()
                   .Select(attr => new Uri(attr.RelativeContentFilePath));

You can also check this page for a way to enumerate BAML resources.


UPDATE : actually the solution above works only for Content files. The method belows returns all resource names (including BAML resources, images, etc) :

    public static string[] GetResourceNames()
    {
        var asm = Assembly.GetEntryAssembly();
        string resName = asm.GetName().Name + ".g.resources";
        using (var stream = asm.GetManifestResourceStream(resName))
        using (var reader = new System.Resources.ResourceReader(stream))
        {
            return reader.Cast<DictionaryEntry>().Select(entry => (string)entry.Key).ToArray();
        }
    }
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • This only works if the assembly has such attributes set - e.g. WPF application would have it set automatically and only for files built with *Content* build action. In case of ClassLibrary assembly there are no such attributes. And even within the assembly code I cannot find the way to enumerate such resources. – Alex_P Mar 25 '10 at 18:35
  • The code in update answers the original question, but still isn't a universal solution :) In case of a class library - it enumerates all resources built with *Content*, *Resource* and *Embedded Resource* build action. But in case of WPF Application it only enumerates resources built with *Embedded Resource* build action. So it seems that in order to enumerate all resources in WPF App the combination of both of the above methods is required. – Alex_P Mar 26 '10 at 10:02
  • Can this piece of code be refined to get resources from a particular folder directly, without the need of filtering the return value? (Say, I have several resource folders (can be seen from the solution explorer), and one of them contains images, which I want to load.) – Ziyuan Oct 07 '11 at 17:14
  • @ziyuang, no, this solution doesn't allow you to specify the path to the resources. But filtering the results is pretty easy using LINQ... – Thomas Levesque Oct 07 '11 at 21:09
  • FYI, for a VB class library, neither approach above worked for me - tried both GetEntryAssembly() and GetExecutingAssembly() for asm. What did work was `Assembly.GetExecutingAssembly().GetManifestResourceNames()`, thanks to http://stackoverflow.com/a/11377846/199364 – ToolmakerSteve Jun 10 '15 at 17:46
  • 2
    @ToolmakerSteve, the code above is for WPF resources, not for standard .NET embedded resources. For embedded resources, GetManifestResourceNames is indeed the way to go. – Thomas Levesque Jun 10 '15 at 21:47
  • Brilliant answer, Thomas! I had the same problem: https://stackoverflow.com/questions/44663908/wpf-c-sharp-reflection-iterate-over-all-resources-with-build-action-page. I slightly changed your code and linked your answer in my question. – Michael Jun 24 '17 at 09:50