¿Cómo puedo descubrir la "ruta" de un recurso integrado?

110

Estoy almacenando un PNG como recurso incrustado en un ensamblado. Desde dentro del mismo ensamblado, tengo un código como este:

Bitmap image = new Bitmap(typeof(MyClass), "Resources.file.png");

El archivo, llamado "file.png" se almacena en la carpeta "Recursos" (dentro de Visual Studio) y está marcado como un recurso incrustado.

El código falla con una excepción que dice:

El recurso MyNamespace.Resources.file.png no se puede encontrar en la clase MyNamespace.MyClass

Tengo un código idéntico (en un ensamblado diferente, cargando un recurso diferente) que funciona. Entonces sé que la técnica es sólida. Mi problema es que termino pasando mucho tiempo tratando de averiguar cuál es el camino correcto. Si pudiera simplemente consultar (por ejemplo, en el depurador) el ensamblado para encontrar la ruta correcta, eso me ahorraría un montón de dolores de cabeza.

Robar
fuente

Respuestas:

198

Esto le dará una matriz de cadenas de todos los recursos:

System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
Juan
fuente
3
Oye, ¿cómo puedo obtener la ruta de la carpeta de recursos para asignarla como directorio raíz para mi servidor http integrado?
lazzy_ms
45

Me encuentro olvidando cómo hacer esto cada vez, así que simplemente envuelvo las dos frases breves que necesito en una pequeña clase:

public class Utility
{
    /// <summary>
    /// Takes the full name of a resource and loads it in to a stream.
    /// </summary>
    /// <param name="resourceName">Assuming an embedded resource is a file
    /// called info.png and is located in a folder called Resources, it
    /// will be compiled in to the assembly with this fully qualified
    /// name: Full.Assembly.Name.Resources.info.png. That is the string
    /// that you should pass to this method.</param>
    /// <returns></returns>
    public static Stream GetEmbeddedResourceStream(string resourceName)
    {
        return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
    }

    /// <summary>
    /// Get the list of all emdedded resources in the assembly.
    /// </summary>
    /// <returns>An array of fully qualified resource names</returns>
    public static string[] GetEmbeddedResourceNames()
    {
        return Assembly.GetExecutingAssembly().GetManifestResourceNames();
    }
}
Dylan
fuente
19

Supongo que tu clase está en un espacio de nombres diferente. La forma canónica de resolver esto sería usar la clase de recursos y un recurso fuertemente tipado:

ProjectNamespace.Properties.Resources.file

Utilice el administrador de recursos del IDE para agregar recursos.

Konrad Rudolph
fuente
Tienes razón, mi clase está en un espacio de nombres diferente. Parece que la carpeta Resources se encuentra en el espacio de nombres especificado como el espacio de nombres predeterminado en la configuración del proyecto, que por varias razones no es el espacio de nombres del que forma parte esta clase. Sospecho que también tiene razón acerca de usar un enfoque completamente diferente, pero como necesito ser consistente con el código heredado, eso está fuera de mi control.
Rob
7
Esto toma el recurso, no la ruta del archivo.
Uchiha Itachi
3
@UchihaItachi Es por eso que ofrecí esta respuesta explícitamente como otra (y posiblemente la canónica) forma de resolver el problema subyacente en lugar de responder la pregunta palabra por palabra (que ya tiene una respuesta en cualquier caso).
Konrad Rudolph
1
@UchihaItachi La pregunta también dice el problema que enfrenta la persona que pregunta, cuál es su enfoque y cómo lo ha intentado hasta ahora. Aunque Rudolph no responde directamente a la pregunta, aborda otro enfoque para resolver el problema. En la mayoría de los casos, este enfoque es más conveniente, seguro y común. Esta respuesta es útil. No entiendo por qué tienes que intentar cerrar las respuestas de la gente. Los botones Vote Up / Vote Down están ahí por una razón.
Nin
5

Utilizo el siguiente método para obtener recursos integrados:

    protected static Stream GetResourceStream(string resourcePath)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        List<string> resourceNames = new List<string>(assembly.GetManifestResourceNames());

        resourcePath = resourcePath.Replace(@"/", ".");
        resourcePath = resourceNames.FirstOrDefault(r => r.Contains(resourcePath));

        if (resourcePath == null)
            throw new FileNotFoundException("Resource not found");

        return assembly.GetManifestResourceStream(resourcePath);
    }

Luego llamo a esto con la ruta en el proyecto:

GetResourceStream(@"DirectoryPathInLibrary/Filename")
masterwok
fuente
3

El nombre del recurso es el espacio de nombre más el "pseudo" espacio de nombre de la ruta al archivo. El "pseudo" espacio de nombres lo crea la estructura de subcarpetas usando \ (barras invertidas) en lugar de. (puntos).

public static Stream GetResourceFileStream(String nameSpace, String filePath)
{
    String pseduoName = filePath.Replace('\\', '.');
    Assembly assembly = Assembly.GetExecutingAssembly();
    return assembly.GetManifestResourceStream(nameSpace + "." + pseduoName);
}

La siguiente convocatoria:

GetResourceFileStream("my.namespace", "resources\\xml\\my.xml")

devolverá el flujo de my.xml ubicado en la estructura de carpetas resources \ xml en el espacio de nombres: my.namespace.

usuario3356450
fuente
6
También los guiones ('-') en las carpetas se reemplazan por guiones bajos ('_'). También puede haber otros símbolos. Me gustaría ver cómo lo está haciendo el compilador para que podamos usar el mismo método.
Boyko Karadzhov