ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

8

Click here to load reader

description

En este documento se explican 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.

Transcript of ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

Page 1: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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:

Page 2: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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

Page 3: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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.

Page 4: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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

Page 5: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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.

Page 6: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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

Page 7: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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.

Page 8: ARTÍCULO: Búsqueda de ensamblados en tiempo de ejecución en .NET

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.