martes, 27 de mayo de 2014

Receta No. 3-5 en C#: Cargar un Assembly en un Dominio de Applicación en Ejecución

Tabla de Contenido

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Clase System.Reflection.Assembly
3.1.1 Método Load
3.1.2 Método LoadFrom
4. Práctica: Código Fuente C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Llega una nueva oportunidad de preparar una otra receta en C#, en la que aprenderemos a cargar assemblies de forma dinámica, es decir, en tiempo de ejecución. Este enfoque, como veremos, es útil para proyectos de software basados en una arquitectura de add-ons o plug-ins (o complementos o agregados), en donde es requerido la agregación y remoción de componentes en caliente: como lo que sucede con los navegadores Web modernos (e.g., Internet Explorer, Chrome, Firefox) que permiten a sus usuarios agregar funcionalidad creadas por terceros (programadores o desarrolladores). ¡Empecemos!

1. Problema

La constructora Narser ubicada en la ciudad de Bogotá (D.C.), precisamente el equipo encargado del área de dirección de servicios de TI (DSTI) , ha concebido una idea de software basado en componentes para sus aplicaciones de producción de tal manera que le permita añadir nueva funcionalidad en corto tiempo a medida que surjan necesidades o cambios en el entorno. Han venido hasta nosotros en busca de asesoría técnica para saber cómo le podemos ayudar en este requerimiento de arquitectura.

2. Solución

Nuestro equipo de asesoramiento de arquitectura conoce profundamente que el Framework .NET cuenta con la maquinaría necesaria para la construcción de soluciones software basadas en componentes. (En un principio, el equipo pretende proponer a DSTI la tercerización del desarrollo a manos nuestras.) Los desarrolladores de Ad Infinitum Systems conocen a fondo el potencial y bondades del namespace System.Reflection. Veamos de qué se trata y por qué soluciona el requerimiento de arquitectura de software modular de nuestro cliente.

3. Discusión de la Solución

Para empezar veamos a través de una ilustración gráfica las ventajas de una arquitectura basada en componentes. En la Figura 1 [4] se muestra la arquitectura basada en COM [6] para el navegador Web Internet Explorer [5].
Arquitectura de Internet Explorer basada en COM
Figura 1. Arquitectura de Internet Explorer basada en COM [4].
La arquitectura de otros navegadores puede ser encontrada en:
  • Mozilla Firefox [7]
  • Google chrome [8]
  • Safari [9].
Después de esta breve introducción a la arquitectura modular o basada en componentes de varios navegadores Web. Miremos algunos de los artefactos en el Framework .NET que permiten alcanzar semejante nivel de reusabilidad, extensibilidad, y mantenibilidad en proyectos de software semejantes.

3.1 Clase System.Reflection.Assembly

La clase Assembly [10] (N:System.Reflection) representa la construcción modular de un assembly (cfr. Creación y Uso de un Módulo) en el Framework .NET. Esta clase es capaz de describir los artefactos integrales de la biblioteca de clases del Framework, como también los propios creados por un programador. Además, ofrece miembros (métodos, precisamente) que permiten cargar un assembly en caliente (con esta expresión me refiero a la posibilidad de cargar nuevos artefactos del modelo, o componentes de terceros, una vez el proyecto haya sido construido (build time)).

En línea con lo anterior, la CLR se encarga de cargar sólo los assemblies incluidos previos al tiempo de construcción (build time). Esta carga se realiza con la lectura de los metadatos del assembly en el momento de uso. Es aquí donde entra en acción la clase Assembly: nos va a permitir realizar cargas posteriores al proceso build time.

Entre los miembros que cuenta la clase Assembly para alcanzar este grado de dinamismo y alusión a la modularidad (modelo de componentes) están los métodos:
  • Load [11], y
  • LoadFrom [12]
Como advierten en [1], la única diferencia entre estos dos métodos es la variabilidad entre los distintos tipos de argumentos que se pueden pasar para cargar un assembly en tiempo de ejecución.

Ahora describamos algunos ejemplos de cada uno de estos métodos para comprender su utilidad de carga de assemblies en tiempo de ejecución.

3.1.1 Método Load

Antes de pasar al ejemplo, en [1] uno describe la forma de operación de Load:
Modo de operación del método Load.
Figura 2. Modo de operación del método Load [1].

Escribamos el siguiente ejemplo de uso de este método (precisamente la versión sobrecargada  [13]):

Firma:

public static Assembly Load(string assemblyString)


Compilamos como una librería DLL:

  1. csc /target:library /out:example.dll AssemblyEjemplo.cs

Archivo UsoAssemblyEjemplo.cs:

La primera línea a destacar en este archivo de código fuente es:

Assembly a = Assembly.Load("assemblyejemplo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");

En donde el argumento del método Load es el nombre de assembly completamente calificado:

assemblyejemplo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Descripción puntual:
  • assemblyejemplo: nombre del assembly.
  • Version=0.0.0.0: versión actual del assembly que queremos cargar.
  • Culture=neutral: especificación de la cultura (regionalización) del assembly.
  • PublicKeyToken=null: null porque no se trata de un assembly (Nombre seguro de assembly)
Compilamos:


  1. csc /target:exe UsoAssemblyEjemplo.cs

Ejecutamos:


  1. .\UsoAssemblyEjemplo.exe

Resultado:
Resultado de carga de assembly en tiempo de ejecución con el método Load.
Figura 3. Resultado de carga de assembly en tiempo de ejecución con el método Load.

3.1.2 Uso del método LoadFrom

Haremos unos pequeños cambios:

1. Hacer una copia del archivo AssemblyEjemplo.dll en la carpeta C:\shared (si no existe, crearla).
2. Crear el archivo UsoLoadFrom.cs:

Observemos que el único cambio que hemos respecto al archivo de código fuente UsoAssemblyEjemplo.cs consisten en la línea 24:

Assembly a = Assembly.LoadFrom(@"C:\shared\AssemblyEjemplo.dll");

En donde al método LoadFrom le especificamos como argumento la ruta absoluta del archivo que contiene el assembly en cuestión.

3. Compilar:


  1. csc /target:exe UsoLoadFrom.cs

4. Ejecutar:


  1. .\UsoLoadFrom.exe

4. Práctica: Código Fuente C#

Veamos un ejemplo extendido en donde conjugamos el uso de los métodos Load y LoadFrom:

Archivo ListadoAssembliesAppDomain.cs:

Compilación:


  1. csc /target:exe ListadoAssembliesAppDomain.cs

Ejecución:


  1. .\ListadoAssembliesAppDomain.exe

Resultado:
Resultado carga de assemblies del GAC con Assembly.Load
Figura 4. Resultado carga de assemblies del GAC con Assembly.Load.

5. Conclusiones

Ha quedado demostrado con teoría y práctica (en particular) el proceso de carga de assemblies en tiempo de ejecución como método de construcción de aplicaciones basadas en componentes (como los navegadores Web). Se usaron los métodos Load y LoadFrom de la clase System.Reflection.Assembly y diferentes formas de paso de argumentos.

6. Glosario

  • AppDomain
  • Assembly
  • Cargar
  • Dominio de aplicación
  • GAC
  • Tiempo de construcción (build time)
  • Tiempo de ejecución

Literatura & Enlaces

[1]: Visual C# 2010 Recipes by Allen Jones and Adam Freeman. Copyright 2010 Allen Jones and Adam Freeman, 978-1-4302-2525-6.
[2]: How to: Load and Unload Assemblies (C# and Visual Basic) - http://msdn.microsoft.com/en-us/library/ms173101.aspx
[3]: AssemblyName.Version Property (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.assemblyname.version.aspx
[4]: Internet Explorer Architecture - http://msdn.microsoft.com/en-us/library/aa741312(v=vs.85).aspx
[5]: Internet Explorer - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/Internet_Explorer
[6]: Arquitectura de Internet Explorer basada en COM - http://en.wikipedia.org/wiki/Component_Object_Model
[7]: web.uvic.ca/~hitchner/assign1.pdf - http://web.uvic.ca/~hitchner/assign1.pdf
[8]: High Performance Networking in Google Chrome - igvita.com - https://www.igvita.com/posa/high-performance-networking-in-google-chrome/
[9]: grosskurth.ca/papers/browser-archevol-20060619.pdf - http://grosskurth.ca/papers/browser-archevol-20060619.pdf
[10]: Assembly Class (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.assembly(v=vs.110).aspx
[11]: Assembly.Load Method (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.assembly.load(v=vs.110).aspx
[12]: Assembly.LoadFrom Method (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfrom(v=vs.110).aspx
[13]: Assembly.Load Method (String) (System.Reflection) - http://msdn.microsoft.com/en-us/library/ky3942xh(v=vs.110).aspx
[14]: R1-9: Asignar un Nombre Seguro a un Assembly desde un Contenedor de Llaves | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/10/r1-9-asignar-un-nombre-seguro-un.html
[15]: R1-3 Creación y Uso de un Módulo | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/10/r1-3-creacion-y-uso-de-un-modulo.html


J

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.