You are on page 1of 8

BÚSQUEDA DE ENSAMBLADOS EN TIEMPO DE EJECUCIÓN EN .NET

Nivel: Intermedio

por José Manuel Alarcón Aguín, www.jasoft.org

A raíz de la duda de uno de mis alumnos de campusMVP (www.campusmvp.com), he decidido

que ensamblados en las aplicaciones.

escribir

cargar

este

documento

explica

los

mecanismos

de

.NET

Para

localizar

y

Las preguntas habituales dentro de esta temática suelen ser: ¿dónde debo colocar los ensamblados que uso en mis aplicaciones? ¿Y cómo hago si quiero compartirlos entre varias aplicaciones?

Trataré de contestarlas a continuación.

En este documento explicaré los tipos de ensamblados que tenemos en .NET, cómo el motor de tiempo de ejecución de la plataforma busca los diferentes ensamblados que usan nuestras aplicaciones, y cómo podemos incluir referencias a ensamblados de la GAC desde Visual

Studio. Finalmente, como apéndice, explicaré un truco para poder ver ensamblados propios en

el diálogo de agregar referencia de Visual Studio.

1.- Tipos de ensamblados

Existen dos tipos de ensamblados en función del uso que se quiera hacer de ellos:

· Ensamblados privados: se identifican por su nombre (el nombre físico del

ensamblado sin la extensión) y se incluyen con la propia aplicación para su uso desde la misma. Son los más comunes y los que utilizamos habitualmente.

· Ensamblados compartidos: se identifican por un su nombre completo (”strong

nameen inglés. Se suele usar más este término anglosajón que mi traducción). Se trata de ensamblados firmados digitalmente para certificar su identidad. En la firma se incluye el nombre del ensamblado pero también otros datos, como su número de versión o la cultura utilizada. Lo más importante es que incluye un testigo de clave pública (public key token) que sirve para comprobar la firma y verificar su autenticidad.

Los ensamblados compartidos se generan con la utilidad de línea de comandos sn.exe, o bien desde el propio IDE de Visual Studio especificando los valores en la pestaña “Firma”, en las propiedades de un proyecto de biblioteca de clases:

Figura 1.- Pestaña de propiedades de firma en un proyecto .NET Para la firma se

Figura 1.- Pestaña de propiedades de firma en un proyecto .NET

Para la firma se utiliza un algoritmo de clave pública, por lo que necesitamos disponer de una pareja de claves pública-privada para el proceso. Podemos reutilizar una pareja de claves que ya tengamos para todos los proyectos (recomendable) o bien generar una nueva usando la lista desplegable que se ve en la figura anterior.

usando la lista desplegable que se ve en la figura anterior. Figura 2.- Diálogo de generación

Figura 2.- Diálogo de generación de nueva pareja de claves de firma

Estos ensamblados compartidos los podemos agregar a la GAC (Global Assembly Cache) del sistema si queremos que puedan ser localizados y utilizados por todas las aplicaciones que

tengamos instaladas, si bien sólo se recomienda con bibliotecas de funciones que realmente se reutilicen mucho.

2.- Búsqueda de ensamblados

Cuando se compila una aplicación, la información sobre los otros ensamblados que ésta utiliza (las referencias) se guardan dentro del manifiesto del ensamblado final que se genera tras la compilación. Es decir, el .exe o .dll que generemos contiene información acerca de los otros ensamblados que se utilizan. Como es lógico, en esta información no se almacenan las rutas de los ensamblados, ya que cualquier cambio de ubicación de la aplicación o de las DLL auxiliares haría que no funcionase. Por ello, lo que se almacena es el nombre o nombre completo (ver apartado anterior) de los ensamblados, y el motor de tiempo de ejecución de .NET los localiza cuando los necesita.

de ejecución de .NET los localiza cuando los necesita. Figura 3.- Manifiesto de un ensamblado con

Figura 3.- Manifiesto de un ensamblado con diversas referencias a ensamblados compartidos del sistema

El mecanismo de búsqueda de ensamblados que se utiliza es ligeramente diferente si éstos son privados o compartidos. A continuación vamos a ver el proceso de búsqueda y carga que hace el runtime de .NET.

3.- Buscar ensamblados privados

Cuando se llama por primera vez a código que está ubicado en un ensamblado privado el motor de tiempo de ejecución de .NET debe cargar en memoria dicho ensamblado, y para ello debe ubicarlo primero en disco. Existe un orden en las diferentes rutas que el runtime va a seguir para ubicar ensamblados.

Lo primero que debemos saber es que cuando se ejecuta una aplicación, el runtime mira el archivo de configuración (.config) de ésta para ver si existe un nodo especial que le indique carpetas adicionales en dónde buscar. Este tipo de nodo es de la siguiente forma:

<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="bin\ruta1;bin\ruta2; " /> </assemblyBinding> </runtime> </configuration>

En el nodo <probing> se especifican rutas relativas a la carpeta en la que está la aplicación, y que puede que contengan (o no) ensamblados para cargar en tiempo de ejecución. Esto es muy útil si nuestro programa usa algún tipo de plug-in que podemos cargar posteriormente de forma dinámica al trabajar con él.

Estas rutas se anotan para utilizarlas luego en la búsqueda de ensamblados.

Conociendo este detalle la búsqueda de ensamblados, entonces, se realiza en las siguientes carpetas y en el siguiente orden pre-establecido:

CarpetaBase\NombreEnsamblado.dll CarpetaBase\NombreEnsamblado\NombreEnsamblado.dll

CarpetaBase\Ruta1\NombreEnsamblado.dll

CarpetaBase\Ruta1\NombreEnsamblado\NombreEnsamblado.dll

CarpetaBase\Ruta2\NombreEnsamblado.dll

CarpetaBase\Ruta2\NombreEnsamblado\NombreEnsamblado.dll

CarpetaBase\NombreEnsamblado.exe CarpetaBase\NombreEnsamblado\NombreEnsamblado.exe

CarpetaBase\Ruta1\NombreEnsamblado.exe

CarpetaBase\Ruta1\NombreEnsamblado\NombreEnsamblado.exe

CarpetaBase\Ruta2\NombreEnsamblado.exe

CarpetaBase\Ruta2\NombreEnsamblado\NombreEnsamblado.exe

Es decir, se buscan primero las DLL y luego los EXE, y primero se intentan localizar dentro de la carpeta actual, y sino dentro de carpetas con el nombre del ensamblado, para finalmente probar dentro de las carpetas sugeridas en el .config (en caso de haberlas).

Si el ensamblado referenciado está atado a una cultura específica, las rutas cambian ligeramente para reflejar este hecho y poder localizar el correcto según la cultura empleada:

CarpetaBase\Cultura\NombreEnsamblado.dll CarpetaBase\Cultura\NombreEnsamblado\NombreEnsamblado.dll

CarpetaBase\Ruta1\Cultura\NombreEnsamblado.dll

CarpetaBase\Ruta1\Cultura\NombreEnsamblado\NombreEnsamblado.dll

CarpetaBase\Ruta2\Cultura\NombreEnsamblado.dll

CarpetaBase\Ruta2\Cultura\NombreEnsamblado\NombreEnsamblado.dll]

CarpetaBase\Cultura\NombreEnsamblado.exe CarpetaBase\Cultura\NombreEnsamblado\NombreEnsamblado.exe

CarpetaBase\Ruta1\Cultura\NombreEnsamblado.exe

CarpetaBase\Ruta1\Cultura\NombreEnsamblado\NombreEnsamblado.exe

CarpetaBase\Ruta2\Cultura\NombreEnsamblado.exe

CarpetaBase\Ruta2\Cultura\NombreEnsamblado\NombreEnsamblado.exe

Es decir, es casi idéntico pero siempre incluyendo el nombre de la cultura delante (por ejemplo, “es-ES”, “en-UK” o simplemente “es” o en.

Con esto resulta fácil saber en qué rutas debemos colocar nuestros ensamblados para que el runtime de .NET los pueda localizar.

4.- Buscar ensamblados compartidos

En el caso de los ensamblados firmados digitalmente o ensamblados compartidos, el proceso es algo diferente y los pasos son los siguientes:

1.- Antes de nada se busca el ensamblado en la GAC del sistema. Si el ensamblado está registrado ahí entonces ya se carga desde la ruta definida en éste y se termina la búsqueda.

2.- Si no está en el GAC se mira el archivo .config de la aplicación para comprobar si existe un elemento <codebase>. Éste se usa para especificar manualmente la ubicación de ciertos ensamblados en una aplicación. Por ejemplo:

<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="miEnsamblado"

publicKeyToken="543rdfa2l9d7e4"

culture="neutral" /> <codeBase version="3.0.0.0" href="http://www.miweb.com/miEnsamblado.dll"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>

De este modo se puede forzar la descarga de una determinada versión de un ensamblado firmado digitalmente desde una ruta concreta en el disco, la red local o incluso Internet (como en el ejemplo).

Si en la configuración hay una línea como esta para el ensamblado que nos interesa, entonces se carga desde ahí y se termina el proceso.

Más

información

sobre

esta

configuración

en:

3.- Si el ensamblado que se busca no se ha cargado en uno de los dos pasos anteriores, entonces se intenta cargar buscándolo como si se tratara de un ensamblado privado, tal como se ha visto en el apartado anterior.

¿Cómo sabe el runtime que el ensamblado es uno compartido y por lo tanto que debe usar este procedimiento? Muy sencillo: porque en el manifiesto se almacena el nombre completo del ensamblado (ver figura 3), el cual incluye la clave pública de firma del mismo. Además gracias a esta se puede comprobar la identidad del ensamblado antes de proceder a cargarlo.

5.- ¿Cómo añado una referencia a un ensamblado en el GAC?

Esta fue en realidad la pregunta que hizo mi alumno, y aunque parece que tiene una respuesta sencilla y directa, no es así.

que tiene una respuesta sencilla y directa, no es así. Figura 4.- Diálogo de agregar una

Figura 4.- Diálogo de agregar una referencia .NET

Cuando abrimos el diálogo de agregar referencias de Visual Studio disponemos de varias pestañas. La primera de ellas se llama simplemente .NETy aparentemente en ella se listan los mismos ensamblados que podemos encontrar en la GAC. Sin embargo si añadimos uno de nuestros ensamblados a la GAC comprobaremos que no aparece en este diálogo.

El motivo es que Visual Studio utiliza unas rutas concretas para llenar esa pestaña del diálogo, no la lista que hay en la GAC como parece a simple vista. Esas rutas, por defecto, coinciden con

las que contienen las DLLs del framework, que son en general las mismas que están en el GAC, de ahí que pueda creerse que son listas idénticas cuando no es así.

Entonces, si tengo una DLL propia en el GAC y no va a aparecer en esta lista, ¿cómo añado una referencia a la misma en mi aplicación?

La respuesta es que si tú tienes un ensamblado firmado sólo debes añadir una referencia al mismo directamente desde Visual Studio, como si de un ensamblado normal se tratara. A mayores lo seleccionas, pulsas F4 para ir a sus propiedades, y marcas la opción de no copiarlo localmente.

propiedades, y marcas la opción de no copiarlo localmente. Figura 5.- Propiedad CopyLocal para evitar que

Figura 5.- Propiedad CopyLocal para evitar que el ensamblado se distribuya

Esto indica que éste no se debe copiar junto con el proyecto. Más tarde, en tiempo de ejecución, cuando el runtime busque el ensamblado en cuestión, dado que es un ensamblado compartido (está firmado), al primer sitio al que irá a buscarlo es al GAC, así que lo usará desde allí como queríamos si lo hemos añadido previamente. Repasa el apartado anterior y lo verás claro.

6.- TRUCO: Añadir una DLL propia al diálogo de añadir referencia .NET

Para terminar voy a explicar cómo podemos hacer que una de nuestras DLL compartidas, que está en el GAC o no, aparezca directamente en el diálogo de añadir referencia, dentro de la pestaña .NET de la figura 4.

Para conseguirlo es necesario tocar el registro, no queda otro remedio.

Las rutas en las que busca este diálogo sus elementos están especificadas en el registro dentro de estas dos ramas:

[HKEY_LOCAL_MACHINE]\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders

[HKEY_CURRENT_USER]\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders

que son, respectivamente, donde buscará elementos para todos los usuarios y para un usuario concreto a mayores. La segunda rama seguramente ni siquiera existe en tu equipo, ya que por defecto no hay nada especial por usuario, claro.

Si quieres que un ensamblado propio aparezca ahí tendrás que introducir en el registro, en alguna de estas ramas, un valor personalizado. Así que creas una sub-rama nueva con el nombre descriptivo que quieras y dentro de ésta, en su valor por defecto, le pones la ruta física de la carpeta que contiene a tus ensamblados.

ruta física de la carpeta que contiene a tus ensamblados. Figura 6.- Rama del registro en

Figura 6.- Rama del registro en la que busca el diálogo

De todos modos esto no tiene mucha utilidad dada la forma que tiene el sistema de buscar ensamblados, según hemos visto. Simplemente te resultará algo más cómodo añadir la referencia, pero nada más.

Acerca del autor

José Manuel Alarcón Aguín, ASP.NET Visual Developer MVP. Es ingeniero industrial y especialista en consultoría de empresa. Ha escrito varios libros, habiendo publicado más de 300 artículos sobre informática e ingeniería en publicaciones especializadas. Es colaborador de MSDN. José Manuel es también Instructor Certificado de Microsoft (MCT). www.jasoft.org

Acerca de campusMVP

CampusMVP te ofrece la mejor formación en tecnología Microsoft a través de nuestros cursos online y nuestros libros especializados, impartidos y escritos por conocidos MVP de Microsoft. Visita nuestra página y prueba nuestros cursos y libros gratuitamente. www-campusmvp.com

nuestros cursos y libros gratuitamente. www-campusmvp.com Reconocimiento - NoComercial - CompartirIgual (by-nc-sa): No

Reconocimiento - NoComercial - CompartirIgual (by-nc-sa):

No se permite un uso comercial de este documento ni de las posibles obras derivadas, la distribución de las cuales se debe hacer con una licencia igual a la que regula esta obra original. Se debe citar la fuente.