Redirección de ensamblados
[Entendiendo los mecanismos de redirección de versiones de ensamblados]

Fecha: 15 de Enero de 2004
Autor: Néstor Soriano - [email protected]

 


Una de las características más interesantes que introduce .NET Framework (al menos según mi opinión) es la llamada "ejecución simultánea". Este pintoresco nombre indica simplemente la capacidad de instalar simultáneamente en un equipo (más concretamente, en la caché de ensamblados global del equipo) varias versiones de un mismo ensamblado, de forma que las aplicaciones compiladas contra la versión X de un ensamblado siempre usarán esa versión aunque estén instaladas las versiones X, Y, Z y J del ensamblado. Una cosa tan aparentemente sencilla resulta sencillamente imposible en la programación "clásica" (basada en DLLs normales y componentes ActiveX) en Windows, dando lugar al problema adecuadamente llamado "infierno de las DLLs" (del que no creo que pueda contarte nada que no sepas ya).

El hecho de que una aplicación siempre use "su" versión del componente es una característica realmente útil, pero en ocasiones las cosas no serán tan sencillas y necesitaremos que la aplicación cargue una versión de ensamblado distinta de aquella para la que ha sido compilada. Este es el caso típico de los componentes de terceros que usamos en nuestras aplicaciones. Imagina, por ejemplo, que obtienes (compras, descargas de Internet, etc) un componente llamado MiBonitoComponente 1.0, y creas una aplicación que usa dicho componente. Algún tiempo después el autor de MiBonitoComponente lanza la versión 1.1, que es totalmente compatible con la versión 1.0 pero resuelve algunos fallos. Naturalmente querrás que tu aplicación use la nueva versión en vez de la antigua.

Sin embargo si instalas la nueva versión del componente verás que la versión nueva y la antigua coexisten (como era de esperar), y que tu aplicación sigue usando la versión 1.0. Si (como seguramente estás pensando ahora) eliminas la versión antigua y dejas instalada sólo la nueva, lo único que conseguirás es que tu aplicación deje de funcionar. Aparentemente la única solución es volver a compilar la aplicación, esta vez contra la nueva versión del componente. Pero esta solución no es la más adecuada por varias razones, la más evidente: puede que la en realidad aplicación no sea tuya y no dispongas del código fuente.

Por fortuna esta situación está prevista en el mundo .NET, y es posible conseguir que tu aplicación use la nueva versión del componente sin tener que volver a compilarla (más formalmente: Es posible forzar a una aplicación a usar versiones de ensamblados distintas de aquellas que figuran en su manifiesto de ensamblado): es lo que se llama Redirección de versiones de ensamblados. Esto se consigue por medio de ficheros de configuración (como veremos enseguida, puede haber hasta tres tipos de ficheros implicados).

Qué vamos a hacer

En lo que queda de artículo vamos a realizar una serie de experimentos que nos ayudarán a comprender cómo funciona la redirección de ensamblados y qué papel juega cada fichero de configuración. Crearemos hasta cuatro versiones de un componente (llamado, lo has adivinado, MiBonitoComponente) y una aplicación (llamada MiAplicacion) compilada contra la primera versión de dicho componente; posteriormente recorreremos todas las opciones de las que disponemos para que la aplicación use una versión distinta del componente.

Tanto el componente como la aplicación son muy sencillos, por lo que no vamos a usar Visual Studio para generarlos y manipularlos; en vez de eso, usaremos directamente las herramientas de línea de comandos que nos ofrece el SDK de .NET Framework. El lenguaje que usaré es Visual Basic, pero obviamente eso es lo de menos; el resultado sería el mismo en caso de usar C# o cualquier otro.

NOTA: En este artículo uso la palabra "componente" con el significado clásico de módulo de código (ensamblado, en este caso) reutilizable; no me refiero al significado que tiene la palabra en el mundo .NET ("clase que hereda de Component o que implementa IComponent").

Primeros pasos

Vamos allá pues. Lo primero será preparar el entorno y generar la primera versión del componente, así como la aplicación que hará uso del mismo.

1) Abre una ventana de intérprete de comandos y crea el directorio c:\vb, donde guardaremos todos los ficheros que vayamos generando.

2) Ejecuta el fichero sdkvars.bat que se encuentra en el directorio C:\Archivos de programa\Microsoft.NET\SDK\v1.1\Bin\ (Nota: Estoy suponiendo que usas la versión 1.1 de .NET Framework; si no es así, el fichero estará en el directorio vX.Y adecuado). Tras esta acción podremos usar todas las herramientas del SDK desde cualquier directorio.

3) Copia tu fichero de claves (el que usas para dotar a tus ensamblados de un nombre seguro) en el directorio vb. Si aún no tienes tal fichero, ahora es el momento de crear uno. Para ello ejecuta el siguiente comando:

sn -k nestor.key

(mi fichero se llama nestor.key; naturalmente, tú puedes usar cualquier otro nombre). Necesitaremos este fichero para firmar el componente con un nombre seguro, requisito indispensable para poder instalarlo en la caché de ensamblados global y así poder usar la ejecución simultánea.

4) Vamos a crear el componente del que tendremos múltiples versiones. Será un componente muy sencillo que únicamente dispondrá de un método, MiBonitoMetodo, que únicamente tendrá un método compartido: ObtenerVersion, que devolverá una cadena con su número de versión.

Abre el Bloc de Notas (o cualquier otro editor de texto) y pega el siguiente código:

Imports System
Imports System.Reflection
Imports System.Diagnostics

<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyKeyFile("c:\vb\nestor.key")>

Public Class MiBonitaclase
    Public Shared Function ObtenerVersion() As String
        Return FileVersionInfo.GetVersionInfo([Assembly].GetExecutingAssembly.Location).FileVersion.ToString
    End Function
End Class

Guarda el fichero con el nombre MiBonitoComponente.vb (recuerda: guarda todos los ficheros en el directorio c:\vb). Observa que deberás modificar adecuadamente el valor pasado al constructor del atributo AssemblyKeyFile si el nombre de tu fichero de claves no es nestor.key.

5) Compila el componente con el compilador de Visual Basic:

vbc MiBonitoComponente.vb /target:library /r:System.dll

6) Instala el componente en la caché de ensamblados global:

gacutil /i MiBonitoComponente.dll

7) Ahora vamos a crear la aplicación que hará uso del componente. Esta sólo la compilaremos una vez, y contra la versión 1.0.0.0 del componente, que es la única que tenemos por ahora.

Pega el siguiente código en el editor de textos:

Imports System
Imports System.Reflection

<Assembly: AssemblyVersion("100.200.300.400")>
<Assembly: AssemblyKeyFile("c:\vb\nestor.key")>

Module MiModulo
    Public Sub Main()
	Console.WriteLine("Versión de MiBonitoComponente: {0}",MiBonitaClase.ObtenerVersion)
    End Sub
End Module

Guarda el fichero con el nombre MiAplicacion.vb (de nuevo, deberás modificar el nombre del fichero de claves si es necesario).

Observa que el número de versión de la aplicación es bastante esotérico. Lo he hecho a propósito para que no pierdas de vista que lo realmente importante en este caso es la versión del componente, no la versión de la aplicación cliente; en realidad ni siquiera es estrictamente necesario que la aplicación tenga asignado un número de versión ni que sea firmada con un nombre seguro.

8) Compila la aplicación con el compilador de Visual Basic:

vbc MiAplicacion.vb /r:MiBonitoComponente.dll,System.dll

La aplicación quedará enlazada a la versión 1.0.0.0 del MiBonitoComponente, ya que esta es la versión del fichero MiBonitoComponente.dll al que hemos añadido una referencia al compilar.

9) Borra el archivo MiBonitoComponente.dll. Este paso no es en realidad necesario, pero nos ayudará a ver más claro el hecho de que cuando nuestra aplicación se ejecuta, carga el componente que hemos instalado la caché de ensamblados global y no el que está en su mismo directorio. Si decides seguir este paso, síguelo cada vez que generes e instales una nueva versión del ensamblado.

10) Bien, pues ya tenemos la aplicación y el componente plenamente funcionales. Para comprobarlo ejecuta MiAplicacion, deberías obtener el siguiente resultado:

Versión de MiBonitoComponente: 1.0.0.0

Vemos que la aplicación obtiene correctamente el número de versión del componente (de hecho, obtener el número de versión es el único servicio que puede obtener por parte de este componente).

Creación de una nueva versión del componente

Ahora vamos a simular el caso en el que el fabricante del componente nos suministra una nueva versión del mismo. Vamos a crear e instalar la versión 2.0.0.0 de MiBonitoComponente, y ver qué pasa con nuestra aplicación.

11) Abre de nuevo el fichero MiBonitoComponente.vb y modifícale el número de versión para que sea 2.0.0.0. Es decir, sustituye el primer atributo por el siguiente y graba el resultado:

<Assembly: AssemblyVersion("2.0.0.0")>

12) Repite los pasos 5 y 6 para generar e instalar la nueva versión del componente.

ATENCIóN: NO vuelvas a compilar la aplicación, pues en ese caso conseguirías que ésta usara directamente la versión 2 del componente, con lo cual todo lo explicado en este artículo pierde su razón de ser. Para mayor seguridad, borra el fichero fuente de la aplicación, MiAplicacion.vb (de todas formas no la vamos a volver a compilar).

Ahora es una buena ocasión para comprobar gráficamente la ejecución simultánea. Abre una ventana del explorador de Windows y navega hasta la caché de ensamblados global (directorio \winnt\assembly). Ordena los ensamblados por nombre, haz scroll hasta encontrar el nombre MiBonitoComponente y comprueba que en efecto, las dos versiones están instaladas simultáneamente, como muestra la siguiente imagen:



NOTA: naturalmente, tú verás un símbolo de clave pública distinto, correspondiente al fichero de claves que estás usando para firmar los ensamblados.

13) Vuelve a ejecutar MiAplicación y comprueba que a pesar de que hemos instalado una nueva versión del componente, sigue usando la versión antigua, y nos muestra de nuevo:

Versión de MiBonitoComponente: 1.0.0.0

Creación de un fichero de configuración de la aplicación

Por fin ha llegado la hora de entrar en materia con el primero de los recursos que tenemos para solucionar el entuerto que tenemos entre manos: los ficheros de configuración de aplicación.

Toda aplicación compilada para funcionar en el entorno .NET puede tener un fichero de configuración en formato XML que será tenido en cuenta por el runtime de .NET cada vez que la aplicación se ejecute. El uso de estos ficheros nos permite modificar ciertos aspectos del comportamiento de la aplicación sin tener que volver a compilarla (en este sentido, son en cierto modo equivalentes a los anitguos ficheros .INI). Entre otras muchas cosas, estos ficheros nos permiten (¿lo adivinas?) redirigir la carga de un ensamblado a una versión distinta de la que figura en el manifiesto de la aplicación.

Enseguida lo verás más claro. Vamos pues a crear un fichero de configuración para MiAplicacion:

14) Pega el siguiente texto en el editor de textos que estés usando:

<?xml version="1.0"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <publisherPolicy apply="yes" />
      <dependentAssembly>
        <assemblyIdentity name="MiBonitoComponente"
                          publicKeyToken="c260f70b6c91be99"
                          culture="neutral" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
        <publisherPolicy apply="yes" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

El formato del fichero de configuración puede parecer complejo a primera vista, pero no te dejes impresionar; de hecho, por ahora sólo nos interesa la parte que está marcada en negrita.

Cada sección <dependentAssembly> especifica la configuración referente al enlace en tiempo de ejecución con uno de los ensamblados de los que depende la aplicación. El elemento <assemblyIdentity> identifica el ensamblado al que nos estamos refiriendo (observa que es obligatorio especificar tanto el nombre como la clave pública y la referencia cultural); y lo que es más interesante, el elemento <bindingRedirect> nos permite redirigir la carga de una ensamblado a otra versión, sin tener que volver a compilar la aplicación. En este caso concreto, el elemento que hemos añadido es como si le dijera al runtime de .NET "¡Oye! Cada vez que esta aplicación te pida la versión 1.0.0.0 de MiBonitoComponente, tú lo que tienes que hacer es servirle en realidad la versión 2.0.0.0", que es precisamente lo que queríamos.

ATENCION: Antes de guardar el archivo, deberás cambiar la cadena asignada al atributo publicKeyToken para que coincida con el testigo de clave pública de tu fichero de claves. Puedes obtener dicho testigo navegando hasta el directorio \winnt\assembly y observando las propiedades de MiBonitoComponente, o bien ejecutando: sn -t nestor.key (usando el nombre real de tu fichero de claves).

Aclarado esto, vamos a seguir con lo nuestro:

15) Graba el fichero con el nombre MiAplicacion.exe.config. Esto es importante: el nombre del archivo de configuración de una aplicación debe ser siempre igual al nombre del propio fichero ejecutable de la aplicación (incluyendo la extensión .exe) más la coletilla ".config" (y, por supuesto, debe estar en el mismo directorio de la aplicación).

16) Ejecuta MiAplicacion y comprueba que, en efecto, el resultado obtenido es ahora:

Versión de MiBonitoComponente: 2.0.0.0

¡Voilá! Ya tenemos a nuestra aplicación usando la versión 2.0.0.0, aunque ha sido compilada contra la versión 1.0.0.0. Pero tranquilo, que esto no ha hecho más que empezar.

Creación de un fichero de directivas del editor

La solución que hemos visto es buena pero no es la mejor posible. Una de las principales características de los componentes que se instalan globalmente es que suelen ser reutilizados por más de una aplicación. Imagina que hay cien aplicaciones en tu máquina que usan MiBonitoComponente (es un poco exagerado, vale, pero supongo que captas la idea). ¿Hay que crear cien ficheros de configuración de aplicación, y modificarlos todos cada vez que obtengamos una nueva versión del componente?

Por fortuna (y como seguramente ya intuías), la respuesta es: no. Es hora ya de meterle mano al segundo recurso disponible para tratar estos casos: el fichero de directivas del editor.

Un fichero de directivas del editor es similar al fichero de configuración de la aplicación, pero va asociado a un ensamblado, y no puede simplemente crearse con un editor de textos y usarse directamente: es necesario compilarlo e instalarlo en la caché de ensamblados global junto con su ensamblado asociado. Una vez hecho esto, la directiva de redirección de versiones que contiene dicho fichero se aplica a todas las aplicaciones que usen el ensamblado.

Como es habitual, lo veremos más claro cuando nos pongamos manos a la obra, así que a eso vamos.

17) Para no confundirnos, primero vamos a inhabilitar el fichero de configuración de la aplicación que hemos creado antes. Para ello no es necesario borrar el fichero; simplemente inhabilita la línea que contiene el elemento <bindingRedirect>. Un elemento de fichero XML se puede inhabilitar insertando una exclamación "!" inmediatamente después del símbolo "<" de apertura. Es decir, la línea quedará como:

<! bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />

Para comprobar que esto es cierto, ejecuta MiAplicacion y comprueba que vuelve a mostrar el número de versión 1.0.0.0, como si no existiera el fichero de configuración.

18) Pega lo siguiente en el editor de textos que estés usando:

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="MiBonitoComponente"
                           publicKeyToken="c260f70b6c91be99"
                           culture="neutral" />
         <bindingRedirect oldVersion="1.0.0.0"
                          newVersion="2.0.0.0"/>
       </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

Como ves es similar al fichero de configuración de la aplicación, pero ahora la redirección especificada se aplicará a todas las aplicaciones que usen el componente.

19) Graba el fichero con el nombre policy.xml. Acuérdate de sustituir antes el testigo de clave pública por el de tu fichero de claves.

20) Ahora generaremos un ensamblado a partir del fichero que acabamos de crear. Para ello usaremos el enlazador de ensamblados de .NET Framework, al.exe, de la siguiente forma (como siempre, cambiando el nombre nestor.key por el de tu fichero de claves):

al /link:policy.xml /out:policy.1.0.MiBonitoComponente.dll /keyfile:nestor.key

Otro punto importante respecto a nombres de fichero. El nombre del fichero XML fuente es irrelevante (hemos usado policy.xml pero podríamos haber usado cualquier otro); pero el nombre del fichero generado debe seguir exactamente este patrón:

policy.version_principal.version_secundaria.nombre_ensamblado.dll

De paso, observa que cada fichero de directivas del editor se aplicará a todas las versiones del ensamblado que compartan los mismos números de versión principal y secundaria. Si el par principal.secundaria del nombre del fichero no coincide con el par especificado en el atributo oldVersion del fichero de directivas, gacutil no te dejará instalar la dll resultante.

21) Instala el fichero dll resultante en la caché de ensamblados global:

gacutil /i policy.1.0.MiBonitoComponente.dll

22) Vamos a ver el resultado. Ejecuta MiAplicacion y obtendrás lo siguiente:

Versión de MiBonitoComponente: 2.0.0.0

Es el mismo resultado que obteníamos con el fichero de configuración de la aplicación, pero con una importante diferencia: la redirección se aplicará a todas las aplicaciones compiladas contra la versión 1.0.0.0 del componente, sin necesidad de crear un fichero de configuración para ninguna de ellas.

Se supone que cada vez que el creador (el "editor") de un componente distribuya una nueva versión compatible con la antigua, junto con el propio componente también entregará el fichero de directivas adecuado, de forma que ambos se instalarán conjuntamente en la caché de ensamblados global. La redirección es por tanto transparente desde el punto de vista de las aplicaciones.

Combinación de un fichero de configuración de aplicación y de un fichero de directivas del editor

De acuerdo, ya hemos visto dos mecanismos de redirección funcionar por separado... pero, ¿qué pasa cuando se usan los dos simultáneamente? Eso es precisament lo que vamos a ver ahora, con la ayuda de una tercera versión del componente. Esta vez pasaremos primero a la acción y dejaremos la teoría para después:

23) Crea e instala la versión 3.0.0.0 de MiBonitoComponente, para lo cual te remito a los pasos 11 y 12.

24) Vuelve a activar el fichero de configuración de la aplicación, simplemente eliminando el "!" que habíamos añadido al elemento <bindingRedirect>. Con esto volvemos a redirigir la carga de MiBonitoComponente a la versión 2.0.0.0 a nivel de aplicación; compruébalo ejecutando MiAplicacion.

25) Crea, compila e instala un nuevo archivo de directivas del editor que redirija la versión 2.0.0.0 a la 3.0.0.0. Para ello, en primer lugar modifica el fichero policy.xml de forma que el elemento <bindingRedirect> quede de esta forma:

<bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0"/>

y a continuación repite los pasos 20 y 21, pero esta vez usando este nombre para el fichero a generar: policy.2.0.MiBonitoComponente.dll

26) Para evitar confusiones, elimina la directiva del editor para la versión 1.0 que hemos instalado antes. Puedes hacerlo de dos formas: navegando hasta \winnt\assembly, seleccionado el fichero policy.1.0.MiBonitoComponente.dll y pulsando la tecla Supr; o bien ejecutando:

gacutil /u policy.1.0.MiBonitoComponente

(ojo: no incluyas la extensión .dll porque en ese caso obtendrás un error).

27) Llegó el momento de la verdad... ejecuta MiAplicacion y comprueba que el resultado obtenido es:

Versión de MiBonitoComponente: 3.0.0.0

Esto merece una explicación, y la explicación es la siguiente: cuando tanto un fichero de configuración de aplicación como una directiva de editor se refieran al mismo componente, se aplicarán ambas redirecciones, pero siempre en el siguiente orden: primero se aplicará lo indicado en el fichero de configuración de la aplicación; y después, sobre el resultado obtenido, se aplicará la directiva del editor.

En este caso concreto, la secuencia de ejecución cuando MiAplicacion intenta cargar MiBonitoComponente es la siguiente:

I. MiAplicacion solicita la versión 1.0.0.0.
II. El fichero de configuración de la aplicación redirige la solicitud de versión 1.0.0.0 a la versión 2.0.0.0.
III. El fichero de directiva de editor redirige la solicitud de versión 2.0.0.0 a la versión 3.0.0.0, que es la que finalmente se carga.

Por supuesto, la cadena no puede romperse: si la aplicación solicitara por ejemplo la versión 1.5.0.0 en vez de la 2.0.0.0, la directiva del editor no se aplicaría, pues ésta sólo se aplica a la versión 2.0.0.0.

Ignorar las directivas del editor

De acuerdo, el creador del componente nos ha suministrado una nueva versión asegurándonos que es compatible con la antigua, y por tanto también nos ha dado el fichero de directivas del editor. Pero resulta que con una aplicación en concreto, la nueva versión del componente da problemas, y queremos seguir usando la versión antigua mientras no encontremos una solución mejor. ¿Cómo lo hacemos?

La solución está de nuevo en el fichero de configuración de la aplicación. Vamos a volver a echarle un ojo, pero esta vez poniendo en negrita un par de elementos en los que anteriormente no nos habíamos fijado:

<?xml version="1.0"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <publisherPolicy apply="yes" />
      <dependentAssembly>
        <assemblyIdentity name="MiBonitoComponente"
                          publicKeyToken="c260f70b6c91be99"
                          culture="neutral" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
        <publisherPolicy apply="yes" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

El elemento <publisherPolicy> nos permite indicar si queremos que las directivas del editor (es decir, lo configurado en el fichero policy.X.Y.nombre.dll) se apliquen o no para esta aplicación en concreto. Observa que hay dos de estos elementos: uno global justo por debajo del elemento <assemblyBinding>, y otro particular dentro del elemento <dependentAssembly>; como habrás podido imaginar, el primero se aplicará a todos los ensamblados que carga la aplicación, mientras que el segundo se aplica únicamente al ensamblado referido por su elemento padre. El comportamiento exacto es como sigue:

  • Si el elemento global está puesto a "no", no se aplicará la directiva del editor para ninguno de los ensamblados que la aplicación carga.


  • Si el elemento global está puesto a "yes", para cada ensamblado a cargar se aplicará la directiva global o no dependiendo del valor concreto de su directiva particular.
Para que termines de verlo claro, te invito a que pruebes diversas combinaciones de "yes" y "no" para los dos elementos (bueno, en realidad en este caso sólo hay cuatro combinaciones posibles) y observes el resultado de cada una de ellas ejecutando MiAplicacion (recuerda: cuando la directiva del editor se cumpla la aplicación dirá que está usando la versión 3.0.0.0 del componente, debido a la redirección doble que hemos visto antes; cuando no se cumpla, usará la versión 2.0.0.0, pues sólo se aplicará la redirección indicada en el fichero de configuración la aplicación).

Por cierto, un comentario importante: el valor por defecto para el elemento <publisherPolicy> cuando no existe dicho elemento en el fichero de configuración es "yes".

El fichero de configuración de la máquina

Bien, pues como si no fuera suficiente con los archivos de configuración de la aplicación y los archivos de directivas del editor, existe un tercer archivo: el archivo de configuración de la máquina. Este fichero es único para cada ordenador (como es lógico), se llama machine.config y está situado en el directorio C:\WINNT\Microsoft.NET\Framework\v1.1.4322\CONFIG (de nuevo, dependiento de tu versión de .NET Framework puedes ver un número vX.X.XXXX distinto).

Una de las cosas que nos permite hacer el fichero de configuración de la máquina es, por supuesto, controlar la redirección de versiones de ensamblados; para ello se usan los elementos <dependentAssembly> que ya conocemos bien. La diferencia es que lo configurado en este fichero se aplicará a todas las aplicaciones que usen los componentes implicados, con independencia de que existan o no ficheros de configuración de aplicación y ficheros de directivas de editor.

Y por supuesto, lo que vamos a hacer ahora es experimentar con este nuevo fichero. Sin embargo, como has sido bueno esta vez no te pediré que edites el fichero a mano, sino que usaremos el asistente de configuración de .NET framework que se instala junto con el SDK. Vamos allá pues:

28) Crea e instala la versión 4.0.0.0 de MiBonitoComponente, para lo cual te remito de nuevo a los pasos 11 y 12.

29) Desde el menú Inicio de Windows, ve hasta Configuración - Panel de Control - Herramientas administrativas - Configuración de Microsoft .NET Framework 1.1

30) Expande el nodo Mi PC, selecciona Ensamblados configurados y pulsa en el enlace Configurar un ensamblado en la página de ayuda que aparece (si no aparece, selecciona Temas de ayuda en el menú Ver).

31) Aparecerá un cuadro de diálogo. Asegúrate de que la casilla Elegir un ensamblado de la caché de ensamblados está activa y pulsa el botón Elegir ensamblado. En la lista que aparecerá selecciona MiBonitoComponente (cualquier versión sirve), pulsa el botón Seleccionar y después el botón Finalizar.

32) En el nuevo cuadro de diálogo que aparecerá, selecciona la pestaña Directiva de enlace. A estas alturas deberías estar viendo lo siguiente (lee la explicación que aparece para saber cómo redirigir un rango de versiones en vez de una sola versión):



Escribe el valor 3.0.0.0 en el cuadro de texto que aparece bajo Versión solicitada y el valor 4.0.0.0 bajo Nueva versión. Finalmente, pulsa el botón Aceptar.

NOTA: Para posteriores modificaciones a la configuración de este mismo ensamblado, bastará que selecciones el ensamblado en la lista que aparecerá al pulsar Ver la lista de ensamblados configurados en la página de ayuda del asistente de configuración (en Mi PC - Ensamblados configurados).

33) Vamos a comprobar que el asistente ha hecho realmente lo que esperábamos. Abre el archivo machine.config y ve hasta el final del mismo (sí: es un archivo muy largo). Comprueba que se ha añadido la siguiente información (usa la función de búsqueda de tu editor si es necesario):

<dependentAssembly>
    <assemblyIdentity name="MiBonitoComponente" publicKeyToken="c260f70b6c91be99" />
    <bindingRedirect oldVersion="3.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>

Por supuesto, habríamos conseguido el mismo efecto escribiendo ese texto directamente en el archivo con el editor de textos, y los cambios se habrían reflejado en el cuadro de diálogo mostrado por el asistente.

Ahora vamos a ver cuál ha sido el efecto de esta nueva configuración:

34) Vuelve a dejar las dos directivas <publisherPolicy> del archivo de configuración de la aplicación a "yes" si las habías modificado.

35) Ejecuta MiAplicacion y comprueba que obtienes:

Versión de MiBonitoComponente: 4.0.0.0

Quizá ya esperabas este resultado, pero por si acaso, te lo explico. Ya hemos visto anteriormente que cuando hay un fichero de configuración de la aplicación y un fichero de directivas del editor que se aplican a un mismo ensamblado, se aplica el primero y después el segundo, siempre en ese orden. Pues bien, si además el fichero de configuración de la máquina hace también referencia al mismo ensamblado, lo dispuesto por este fichero se aplica después de que se apliquen los otros dos ficheros. Es decir, tenemos ahora una cadena de cuatro pasos:

I. MiAplicacion solicita la versión 1.0.0.0.
II. El fichero de configuración de la aplicación redirige la solicitud de versión 1.0.0.0 a la versión 2.0.0.0.
III. El fichero de directiva de editor redirige la solicitud de versión 2.0.0.0 a la versión 3.0.0.0.
IV. El fichero de configuración de la máquina redirige la solicitud de versión 3.0.0.0 a la versión 4.0.0.0, que es la que finalmente se carga.

Un último apunte: si bien se puede impedir que se apliquen las directivas del editor mediante los elementos <publisherPolicy> del fichero de configuración de la aplicación, no hay forma de impedir que se aplique lo dispuesto por el archivo de configuración de la máquina.

BONUS: Modificar el fichero de configuración de la aplicación con el asistente

Como premio a tu paciencia y esfuerzo, para terminar voy a explicarte cómo se puede configurar la redirección de ensamblados a nivel de aplicación (es decir, cómo modificar MiAplicacion.exe.config) usando un asistente disponible similar al que hemos usado para modificar el fichero de configuración de la máquina.

36) De nuevo, ve a: Inicio - Configuración - Panel de Control - Herramientas administrativas - Configuración de Microsoft .NET Framework 1.1, y expande el nodo Mi PC.

37) Sitúate sobre el nodo Aplicaciones, y en la página de ayuda pulsa en el enlace Agregar una aplicación para configurar. Selecciona MiAplicacion en la lista que aparecerá (si no aparece, pulsa el botón Otras y búscala).

Ahora puedes comprobar que MiAplicacion cuelga del nodo Aplicaciones, siendo en sí misma otro nodo.

38) Expande el nodo MiAplicacion.exe y selecciona Ensamblados configurados. En la página de ayuda que aparece, pulsa el enlace Configurar un ensamblado.

39) Aparecerá un cuadro de diálogo similar al que apareció cuando configurabas el fichero de la máquina. Esta vez marca la opción Elegir un ensamblado de la lista de ensamblados que utiliza la aplicación, pulsa Elegir ensamblado, selecciona MiBonitoComponente y pulsa Seleccionar y Finalizar.

40) En el cuadro de diálogo que aparece, selecciona la pestaña Directiva de enlace y... sorpresa: vemos lo mismo que en la figura que te he enseñado antes, pero la lista de redirecciones no está vacía: muestra una redirección de la versión 1.0.0.0 a la versión 2.0.0.0. Por supuesto, esta información ha sido obtenida desde el fichero MiAplicacion.exe.config que habíamos creado a mano.

Esa es la tónica general: los cambios que hagas desde el asistente se reflejarán en el fichero XML asociado, y viceversa. De paso, te comento que si el fichero de configuración de la aplicación no existe cuando uses el asistente, se creará uno nuevo.

NOTA: Quizá ahora estás esperando que te muestre cómo crear e instalar un archivo de directivas del editor usando un asistente... pero no puedo hacer eso sencillamente porque no existe ningún asistente para esa tarea. La única forma de crear un archivo de directivas del editor es la forma manual que te he enseñado.

Conclusión

Bueno, ha sido un largo viaje pero ha valido la pena (espero) porque ahora la redirección de versiones de ensamblados no tiene secretos para ti. Y de paso ya conoces los tres tipos de ficheros de configuración que existen, aunque como ya imaginarás, éstos ofrecen mucho más que la simple redirección de ensamblados. Pero eso es otra historia, y seguramente mucho más larga que ésta.

NOTA: No incluyo los ficheros con el código fuente porque lo importante en este artículo es que los ficheros sean generado en el orden indicado, y tenerlos todos desde el principio no tendría mucho valor didáctico. Además se trata de ficheros pequeños y no hay mucho que teclear.


ir al índice