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


escribir este documento que explica los mecanismos de .NET Para localizar y cargar
ensamblados en las aplicaciones.

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
name” en 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 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.

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.

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: http://msdn.microsoft.com/es-


es/library/efs781xb.aspx.
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í.

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 “.NET” y 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.

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.

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

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.