4
votes

I currently use GetManifestResourceStream to access embedded resources. The name of the resource comes from an external source that is not case sensitive. Is there any way to access embedded resources in a case insensitive way?

I would rather not have to name all my embedded resources with only lower case letters.

3
Darrel, do you have a list of the embedded resource names but simply don't know the case? e.g., you know that: MyBitmap MyText are embedded but could be named: MYBITmap myTEXT ? - Mark
The name of the resource comes in over an Url. I don't want the url to be case sensitive, but I have no way to map to the case-sensitive resources without a big manually maintained switch. - Darrel Miller
The function below might help. I posted it before I read you return comment. The intention behind this function is maintaining a lookup table. I think that's going to be the best approach given the restrictions in the framework - Mark

3 Answers

13
votes

Assuming that you know the resource names from the external source and are only lacking the capitalization, this function creates a dictionary you can use for lookups to align the two sets of names.

you know -> externally provided
MyBitmap -> MYBITMAP
myText -> MYTEXT

/// <summary>
/// Get a mapping of known resource names to embedded resource names regardless of capitlalization
/// </summary>
/// <param name="knownResourceNames">Array of known resource names</param>
/// <returns>Dictionary mapping known resource names [key] to embedded resource names [value]</returns>
private Dictionary<string, string> GetEmbeddedResourceMapping(string[] knownResourceNames)
{
   System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
   string[] resources = assembly.GetManifestResourceNames();

   Dictionary<string, string> resourceMap = new Dictionary<string, string>();

   foreach (string resource in resources)
   {
       foreach (string knownResourceName in knownResourceNames)
       {
            if (resource.ToLower().Equals(knownResourceName.ToLower()))
            {
                resourceMap.Add(knownResourceName, resource);
                break; // out of the inner foreach
            }
        }
    }

  return resourceMap;
}
3
votes

If you don't want to create a dictionary upfront then this will work.

private static Stream GetResourceStream(string name)
{
    var assembly = Assembly.GetExecutingAssembly();

    // Replace path separators with '.' separators 
    var path = string
        .Concat( assembly.GetName().Name, ".", name)
        .Replace('/','.')
        .Replace('\\','.');

    // Match using case invariant matching
    path = assembly
        .GetManifestResourceNames()
        .FirstOrDefault(p => p.ToLowerInvariant() == path.ToLowerInvariant());

    if(path==null)
        throw new ArgumentNullException($"Can't find resource {name}",nameof(name));

    var manifestResourceStream = assembly.GetManifestResourceStream(path);
    if (manifestResourceStream == null)
        throw new ArgumentNullException($"Can't find resource {name}",nameof(name));

    return manifestResourceStream;
}
0
votes

Similar answer to the accepted one above, but I wanted to share my solution in VB.NET.

''' <summary>
''' Gets the file name in its proper case as found in the assembly.
''' </summary>
''' <param name="fileName">The filename to check</param>
''' <param name="assemblyNamespace">The namespace name, such as Prism.Common</param>
''' <param name="assembly">The assembly to search</param>
''' <returns>The file name as found in the assembly in its proper case, otherwise just filename as it is passed in.</returns>
''' <remarks></remarks>
Public Shared Function GetProperFileNameCaseInAssembly(ByVal fileName As String, ByVal assemblyNamespace As String, ByVal assembly As System.Reflection.Assembly) As String
    For Each resource As String In assembly.GetManifestResourceNames()
        'Perform a case insensitive search to get the correct casing for the filename
        If (resource.ToLower().Equals(String.Format("{0}.{1}", assemblyNamespace, fileName).ToLower())) Then
            'cut off the namespace assembly name in the resource (length + 1 to include the ".") to return the file name
            Return resource.Substring(assemblyNamespace.Length + 1)
        End If
    Next
    Return fileName 'couldn't find the equivalent, so just return the same file name passed in
End Function