DNM+ Online
dotnetmania 2.0
WCF Configuraciones e instaladores
El despliegue de los servicios y clientes WCF en diferentes entornos (desarrollo, preproducción, producción) es una tarea propensa a errores en la que normalmente se hace necesario “tocar” manualmente los archivos de configuración. En este artículo se presenta una propuesta para simplificar el despliegue de nuestros servidores y clientes WCF mediante proyectos de instalación que solicitan la dirección de los servicios y actualizan automáticamente estos archivos.

Creo que lo que mejor manera de definir a los que nos dedicamos a esto del software es llamarnos vagos. ¿Para qué vamos a hacer lo mismo dos, tres, N veces, si podemos programarlo una vez y despreocuparnos? Esto me ha pasado con los archivos de configuración de WCF y quiero compartir con vosotros cómo lo he resuelto. No creo que os descubra nada nuevo si digo que WCF "mola un huevo". Podemos montar la estructura de comunicaciones tanto en un archivo de configuración como directamente por código. En los proyectos en los que he participado, con el archivo de configuración me ha sobrado; por eso, seguramente, es el método que más me gusta. Un archivo XML en el que se basan las comunicaciones de nuestro sistema. Los archivos de configuración han estado siempre ahí, siempre los hemos usado, pero gracias a la abstracción, patrones de diseño y todo lo que ha hecho que el desarrollo de software se convierta en una ingeniería, podemos tener componentes tan generales como personalizables. ¿Veis por dónde voy? A mí no me gusta desarrollar software: me encanta. Lo haga mejor o peor. Y aunque sepa que es una ingeniería, personalmente lo considero un arte. El "problema" cuando estamos desarrollando con WCF es a la hora de poner el sistema en un entorno de desarrollo, de preproducción o en producción. Me explico. En desarrollo, montamos nuestros servicios en nuestra máquina local, decidimos qué bindings nos convienen más, creamos los servicios, los configuramos y empezamos con los consumidores. Todo perfecto; esto es la leche. Pero luego toca montarlo todo en un(os) servidor(es) de desarrollo, y entonces saltan las alarmas: tenemos que trastear con los archivos de configuración para que los servicios funcionen en el(los) servidor(es) de desarrollo. ¿Tenemos que cambiarlos a mano? ¿En preproducción y en producción también? Trivial: tenemos los proyectos de instalación [1] y LINQ to XML [2]… Qué tonto puedo parecer algunas veces. En este artículo vamos a ver cómo con un simple instalador vamos a poder desplegar todo el sistema sin tener que estar tocando a mano esos archivos de configuración. Con un instalador en plan "Siguiente, Siguiente, Aceptar" tendremos nuestro sistema desplegado y configurado. Para simplificar un poco, en Visual Studio 2008 tendremos una solución con dos proyectos de consola: uno llamado Servidor, que va a servir de host a un servicio WCF, y otro (Cliente) que va a hacer de cliente.
Una vez que añadimos un servicio WCF al proyecto Servidor, ya tenemos el primer App.config de la "discordia": el que nos va a permitir configurar la forma de comunicarse con los clientes. Las operaciones que publique nuestro servicio no son relevantes para este artículo, ya que lo que nos interesa es cómo automatizar el proceso de actualización de los archivos App.config. Y digo "los" porque al agregar la referencia al servicio WCF en el cliente, también nos va a aparecer otro… que también habrá que configurar en producción.
Ahora lo que nos queda es crear un proyecto de instalación para nuestras aplicaciones, tanto el servidor como la aplicación cliente. Vamos a ver cómo crearíamos el proyecto de instalación del proyecto Servidor para que nos pregunte por la dirección en la que queremos publicar nuestros servicios. Lo primero es añadir un proyecto de instalación a la solución (figura 1). En el cuadro de diálogo de tipos de proyecto, debemos seleccionar el nodo "Setup and Deployment" (Instalación y despliegue), que se encuentra en la categoría "Other Project Types" (Otros tipos de proyectos), y la plantilla "Setup Project" (Proyecto de instalación). A continuación, tenemos que añadir el resultado de la compilación del proyecto Servidor, indicándole así al proyecto de instalación qué es lo que queremos instalar. Para ello, en el Explorador de soluciones hacemos clic con el botón derecho en el proyecto de instalación, y seleccionamos la opción "Add" | "Project Output". En el cuadro de diálogo que aparece, indicamos que queremos añadir la salida de compilación del proyecto Servidor. Allí, en el desplegable "Configuration" podemos indicar que se utilice la configuración activa, "Debug" o "Release". Esto va a depender de los gustos y de lo olvidadizos que seamos a la hora de generar y compilar nuestros ensamblados. Personalmente, prefiero la opción "Release"; así no tengo que acordarme de cambiar la configuración de compilación de Visual Studio a la hora de generar el instalador.

Una vez agregada la salida del proyecto Servidor, tenemos que añadir una acción personalizada (Custom Action) para la instalación. Para ello, en el Explorador de soluciones hacemos clic con el botón derecho en el proyecto Instalador y seleccionamos en el menú contextual "View" | "Custom Actions". En la pestaña que aparece, hacemos clic con el botón derecho en "Custom Actions" y seleccionamos "Add Custom Action". Y en el cuadro de diálogo subsiguiente, nos vamos a "Application Folder" y seleccionamos la salida principal (Primary Output) del proyecto que acabamos de añadir.
Si en este momento compilamos y ejecutamos el instalador, nos preguntará por la ruta en la que queremos instalar. Y en esa ruta nos copiará tanto el ejecutable como su archivo de configuración.

Solo nos queda hacer que el instalador nos pregunte en qué dirección queremos publicar los servicios. Tenemos que añadir un cuadro de diálogo a la interfaz del instalador con un cuadro de texto en el que se podrá indicar esa dirección. Para ello, en el Explorador de soluciones hacemos clic con el botón derecho sobre el proyecto Instalador y seleccionamos en el menú contextual "View" | "User Interface". En la nueva pestaña que aparece, nos vamos al nodo "Install" | "Start", hacemos clic con el botón derecho y seleccionamos "Add Dialog", y luego el diálogo predefinido "TextBoxes (A)" (figura 2). Una vez añadido el diálogo, en el árbol donde se nos muestran los diferentes pasos del proceso de instalación aparecerá un nuevo elemento. Debemos posicionarlo después del de bienvenida ("Welcome"). El cuadro de diálogo predefinido que hemos añadido ofrece cuatro cuadros de texto. Como solo necesitamos uno, en las propiedades de ese cuadro de dialogo cambiaremos los valores de Edit2Visible, Edit3Visible y Edit4Visible a false, para que no aparezcan durante la instalación. Si en este punto compilamos y ejecutamos el instalador, veremos éste incluirá ahora un nuevo paso con el cuadro de diálogo que recién hemos añadido después de la bienvenida. Por último, solo nos queda recoger el dato que se introduzca en el cuadro de texto del diálogo y actualizar con él el archivo de configuración. Para ello, necesitamos agregar a la solución un nuevo proyecto de tipo Librería de clases que contenga una clase especial que va a ser llamada cuando se ejecute la instalación. Llamaremos a este proyecto AyudaInstalacion. Al crearlo, Visual Studio nos agregará por defecto una clase que no nos va a hacer falta, así que la eliminamos. Entonces añadimos al proyecto un elemento de tipo InstallerClass, al que llamaremos ActualizarConfiguracion (figura 3). Con esto se añadirán al proyecto las referencias a todos los ensamblados necesarios que van a hacer posible la ejecución del código que escribamos cuando se instale nuestro Servidor. Si nos vamos a la vista de código del elemento añadido, veremos que se trata de una clase que hereda de la clase Installer de .NET Framework. Esta clase implementa toda la funcionalidad necesaria para operar en el contexto de una instalación, y nos permite sobrescribir ciertos métodos que se van a ejecutar en determinados momentos de la instalación. Aquí lo que queremos es que en el momento de la instalación se actualice el código del archivo de configuración con la dirección que se haya suministrado durante el proceso.
Tenemos que añadir otro "Primary Output" al proyecto de instalación, como ya hicimos anteriormente, pero esta vez añadimos el proyecto AyudaInstalación. La idea es que el instalador despliegue con el proyecto la librería de clases, a la que llamaremos para que se encargue de actualizar el archivo de configuración. Como cabría esperar, la llamada a la librería de clases debemos implementarla como otra acción personalizada, aunque esta vez la añadimos debajo del nodo "Install" (figura 4). Y como deberemos pasarle el texto que se haya introducido en el cuadro de texto para que sepa con qué actualizar el App.config, seleccionamos "Primary output from Ayudainstalacion" y modificamos su propiedad CustomActionData como se muestra en la figura 4. De esta manera indicamos que lo que se escriba en el cuadro de texto con nombre "EDITA1" se debe guardar en el contexto de la instalación bajo la clave "direccion", lo que hará que ese valor sea accesible para el código de la acción personalizada que acabamos de añadir. Finalmente, vamos al proyecto AyudaInstalacion y escribimos el código necesario para actualizar el archivo App.config. En la clase ActualizarConfiguracion, sobrescribimos el método Install como se muestra en el listado 1. En el código, inicialmente se obtiene la ruta completa del archivo de configuración, que va a ser la concatenación de la ruta de instalación y el nombre del archivo de configuración. La ruta de instalación también se pasa como un parámetro en el contexto de la instalación, y el nombre del archivo de configuración es Servidor.exe.config (o Cliente.exe.config para el proyecto Cliente). A continuación, y una vez obtenida la dirección que se ha pasado al instalador (que debería validarse mediante expresión regular u otra técnica), se carga el contenido del archivo de configuración en un XElement y se modifican los elementos y los atributos que nos interesan. Lo que necesitamos es cambiar el valor del atributo baseAddress, reemplazando en él "localhost" por la dirección pasada al instalador. Gracias a LINQ to XML, esta tarea puede llevarse a cabo de una manera muy sencilla.

Conclusión A lo largo de este artículo, hemos mostrado cómo crear un proyecto de instalación personalizado que nos permita especificar en tiempo de instalación la dirección de nuestros servicios WCF. De esta manera, cada vez que vayamos a desplegar nuestro servidor no tendremos que tocar las configuraciones a mano, cosa muy tendiente a errores. Solo tendremos que pasarle la dirección durante la instalación, y nuestros servicios quedarán configurados, preocupándonos tan solo una vez sobre cómo vamos a configurarlos en desarrollo, y olvidándonos de este tema en lo adelante. Esta misma técnica podemos aplicarla exactamente de la misma manera a las aplicaciones clientes.

blog comments powered by Disqus
autor
referencias