miércoles, 10 de febrero de 2010

Creación de programas de instalación para ASP.NET con VS 2005

Escenario
Habéis echo una aplicación web ASP.NET con Visual Studio 2005, y queréis permitir a vuestros clientes que puedan instalar y desplegarla en sus servidores a través de un programa de instalación.
Concretamente, quereis crear un programa de instalación estándar de Windows que cree y configure la aplicación en el IIS, que copie todos los archivos necesarios para la aplicación en el servidor, y comprobar que ASP.NET 2.0 está correctamente configurado para que se ejecute la aplicación. También queréis que el programa de instalación le pregunte al cliente por la localización de la base de datos que usará la aplicación, y que actualize automáticamente el archivo web.config con las cadenas de conexión a la base de datos que el cliente proponga.
Una solución a considerar es usar el tipo de proyecto “Web Setup Project” que viene con Visual Studio. Este tipo de proyectos pueden usarse para encadenar los resultados de la compilación tanto de proyectos de aplicaciones web de Vs 2005 como para sitios web (cuando usamos Web Deployment Projects), para crear programas de instalación de windows encapsulados. En la siguiente guía mostramos cómo crearlos y usarlos paso a paso.
1) Crear una aplicación web con VS 2005.
Lo primero que debemos hacer es abrir una instancia nueva de Vs 2005 y crear un proyecto de aplicación web (Web Application Project) (En Archivo/New Project/Aplicación Web ASP.NET). Para este ejemplo tendremos dos páginas en el proyecto:

Añadiremos una etiqueta (label) a la página Default.aspx y un manejador para el evento Page_Load en el code-behind para mostrar la fecha y hora actual en cada petición. Cuando pulsemos F5 para compilar y ejecutar la aplicación, el proyecto se compilará y ejecutará como habíamos esperado (y por defecto usaremos el servidor web de pruebas que viene en Visual Studio):

2) Añadir un proyecto de Instalación Web a la solución.
Ahora que tenemos una aplicación web ASP.NET, añadiremos un proyecto de instalación web (Web Setup Project) a la solución. Seleccionamos Archivo\Añadir\Nuevo Projecto para añadirlo a la solución:

Fijaos que el “Proyecto de instalación Web” se muestra en “Otro tipo de proyecots \ Setup and Deployment”. Le ponemos el nombre que queramos y le damos a OK. Se mostrará como un proyecto separado en el explorador de soluciones.
Lo siguiente es configurar el proyecto de instalación para que coja los asemblies precompilados (directorio \bin) + los archivos .aspx, .config, etc de nuestra aplicación web para usarlas como entradas en nuestro proyecto de instalación. Para hacer esto, hacemos clic con el botón derecho en proyecto de instalación web en el explorador de soluciones y elejimos “Añadir\Proyecto de salida”:

Aparecerá un cuadro de diálogo que nos permitirá seleccionar un proyecto de la solución, y qué contenido del proyecto queremos añadir al paquete de instalación:

Para los proyectos de aplicación web es muy importante que seleccionemos tanto “Primary Output” (que son los assembiles compilados del directorio \bin) como los “Content files” (que son los archivos .aspx)Por defecto, el proyeto de instalación web copiará estos elementos a la raíz de la aplicación web que generará el proyecto de instalación web. Podemos ver que está configurado de esta manera abriendo la vista de “Sistema de archivos” del proyecto de instalación web (clic derecho en la raíz del proyecto de instalación y seleccionar Ver\Sistema de Archivos:

Esto no es lo que queremos que pase, ya que lo que realmente queremos es que los assemblies ( indicados en el nodo Primary Output) sean copiados al directorio \bin de la aplicación (de otra forma ASP.NET no será capáz de encontrarlos en tiempo de ejecución). Para arreglarlo, arrastramos/soltamos el nodo “Primary Output de MyApplication” en el directorio \bin. Una vez echo esto seremos capaces de hacer clic en el nodo “Directorio de la aplicación Web” en la parte izquierda y ver esto:

Y haciendo clic en el directorio “bin” veremos esto:

Ahora tenemos un proyecto de instalación básico creado y configurado para nuestra aplicación web ASP.NET. El siguiente paso es compilarla y ejecutarla.
3) Compilar y ejecutar el proyecto de instalación.
Para compilar el proyecto de instalación web, podemos hacer clic con el botón derecho en el nodo del proyecto de instalación web en el explorador de soluciones y elegir la opcion “Build”:

Si habrimos la ventana de output de VS (Ver\Resultados), veremos los resultados de la compilación:

El projecto “MyApplicationSetup” ha creado un instalador de windows, ha comprimido y ha empaquetado el contenido de nuestra aplicación web ASP.NET en el archivo MyApplicationSetup.msi. (Nota: en las propiedades del proyecto de instalación podéis elegir el algoritmo de compresión a usar, podemos decirle que lo optimize en tamaño o en velocidad).
Muy importante: Debido a que los proyectos de instalación tardan un rato en compilarse, no se marcan por defecto para que se compilen como parte de la solución. Esto significa que tenemos que hacer clic derecho en ellos para compilarlos explícitamente. Hay que tener cuidado cuando hacemos y provamos cambios – de otra forma estaremos ejecutando la versión previa de la versión compilada y no la última con el código más actualizado.
Para probarlo, podemos hacer clic con el botón derecho en el proyecto de instalación en el explorador de soluciones y seleccionar la opción “Install” para instalarlo. (o podemos lanzarlo fuera de VS ejecutándolo):

Con esto lanzaremos el instalador estándar de Windows que guiará al usuario para instalarlo en el IIS:


Los proyectos de instalación web de VS 2005 nos permiten seleccionar el sitio donde instalar la aplicación si hay varios sitios configurados en el IIS (Esto no estaba soportado en la versión 2003 de Visual Studio). También podemos especificar un directorio virtual para instalar la aplicación (por ejemplo: http://www.myserver.com/myapppath),
o podemos dejar ese campo en blanco para instalar la aplicación en la raíz de nuestro sitio (por ejemplo http://www.myserver.com/).
Una vez que el instalador termina, la aplicación se habrá copiado al disco y se habrá registrado en el IIS. Ahora podemos ejecutar la aplicación usando la dirección http que le dijimos en la instalación:

Una vez instalada, la aplicación se mostrará en la utilidad de “Añadir o quitar programas” del Panel de Contol de Windows:

También podemos desinstalar la aplicación desde esta utilidad, o (en tiempo de desarrollo) haciendo clic con el botón derecho en el proyecto de instalación en el explorador de soluciones y seleccionando la opción de “Desinstalar”. Esto borrará todos los archivos instalados del disco.
4) Actualizar la interfaz del Wizard del proyecto de instalación web.
Por defecto, el instalador que se crea por un proyecto de instalación web tiene por defecto algunas instrucción en cadenas y en imágenes:

Podemos cambiar esto y personalizar las pantallas haciendo clic con el botón derecho en el nodo del proyecto de instalación web en el explorador de soluciones seleccionando “View \ User Interface” :

Esto nos mostrará una pantalla que nos muestra la lista de pantallas que se mostrarán durante el proceso de instalación:

Desafortunadamente no hay un diseñador de forms que podamos usar para sobreescribir las pantallas de arriba. Sin embargo, podemos seleccionar una pantalla, e irnos a las propiedades para personalizar el texto y cambiar los gráficos que se usarán en la pantalla:

También podemos crear nuevas pantallas y añadirlas al wizard de instalación. Más tarde en este tutorial usaremos esta característica para crear una pantalla para obtener la cadena de conexión y usarla para automatizar la configuración de nuestro archivo web.config para poder usar la base de datos apropiada.
5) Añadir acciones personalizadas al Proyecto de Instalación Web de VS 2005
Los proyectos de instalación web tienen soporte para configurar ciertas cosas comunes de instalación. Entre otras existe un editor para añadir/modificar entradas del registro (seleccionando View\Register to configure), cambiar asociaciones de archivos (View\File Types), y para validar prerrequisitos necesarios para la instalación (automáticamente comprueba que el .NET Framework 2.0 redistributable esté instalado). Los proyectos de instalación también nos permiten configurar unas cuantas opciones de IIS declarativamente (clic en el “directorio de la aplicación web” en la vista de File System y miremos las propiedades para ver esto):

Pero para instalaciones que no sean triviales, lo más normal es poder ser capaz de ejecutar codigo personalizado durante la instalación para personalizar cosas. Las buenas noticias es que los proyectos de instalación web soportan una cosa llamada “Custom Actions” (Acciones personalizadas) - que es el código
que escribiremos que se ejecutará tanto en la instalación como en la desinstalación.
Para añadir una acción personalizada lo primero que debemos hacer es añadir un nuevo proyecto de librería en la solución (Archivo\Añadir\Nuevo proyecto\Librería de clases).
Luego tenemos que añadir unas referencias a algunos assemblies: System.Configuration.Install.dll, System.Configuration.dll, System.Diagnostics.dll y System.Web.dll. Luego creamos una nueva clase para
nuestra acción personalizada y debe derivar de la clase “System.Configuration.Install.Installer” :
using System;
using 
System.Configuration.Install;
using 
System.ComponentModel; namespace MyCustomAction
{
    [RunInstaller(
true)]
    
public class ScottSetupAction : Installer
    {
        
public override void Install(System.Collections.IDictionary stateSaver)
        {
            
base.Install(stateSaver);            // Todo: Write Your Custom Install Logic Here
        
}
    }
}
Hay que fijarse en que el atributo “RunInstaller(true)” debe estar
encima del nombre de la clase. Esto es importante y es necesario (y fácil de
olvidar). Necesitamos añadir un using al namespace System.ComponentModel 
para ello.

Lo siguiente que necesitaremos es asegurarnos de que este assemblie de acción personalizada se añadirá al proyecto de instalación web. Para ello, hacemos clic con el botón derecho en el proyecto de instalación web en el explorador de soluciones y seleccionamos la opción View\File System. Hacemos clic derecho en el subdirectorio “bin” y seleccionamos “añadir\Project Output” como hicimos ántes para añadir esta acción personalizada al proyecto de instalación web:

En este caso queremos seleccionar la librería de clases de acciones personalizadas en lugar de la aplicación web. Lo seleccionamos de la lista desplegable de proyecto encima del diálogo y seleccionamos la opción de “Primary Output” como la pieza que queremos añadir a nuestro proyecto de instalación web (esto hará que se añada nuestra acción personalizada):

Por último, configuraremos nuestro proyecto de instalación para que llame a nuestra acción personalizada durante la fase de instalación. Para esto, hacemos clic derecho en el proyecto de instalación web en el exporador de soluciones “View\Custom Actions”. Esto nos mostrará el editor de Aciones Personalizadas.
Clic derecho en el nodo “Install” y elegimos “Add Custom Action”:
Nos dirigimos al directorio Bin de la aplicación web y elegimos la salida de la ación personalizada que importamos:

El proyecto de Instalación detectará automáticamente la acción personalizada gracias al atributo “RunInstaller”:

La clase de acción personalizada y el método de instalación se ejecutará ahora todas las veces que ejecutemos el programa de instalación.
6)Ejemplo de una acción personalizada útil: ASP.NET Script Mapping Checker
La última sección vimos cómo crear y configurar una acción personalizada vacía y un método de instalación. Hagamos ahora algo útil con ello. En concreto, añadiremos código para comprobar que la versión correcta de ASP.NET está mapeada correctamente para la aplicación que estamos creando.
Debido a que ASP.NET 1.1 y 2.0 pueden estar ejecutándose en la misma máquina, es posible tener configuradas varias partes del servidor web para que funcionen usando diferentes versiones de ASP.NET. Por defecto, las versiones se heredan jerárquicamente – es decir, si la aplicación raíz de un sitio está configurada para usar ASP.NET 1.1, todas las aplicaciones que pongamos bajo ese directorio raíz usarán por defecto la versión 1.1 también. Lo que haremos en los pasos siguientes es escribir algun código para asegurarnos de que nuestra nueva aplicación se ejecutará usando siempre ASP.NET 2.0
Para empezar, seleccionamos nuestra acción personalizada en el explorador de Custom Action (como en la sección anterior: “View\CustomAction”), nos vamos a las propiedades y especificaremos algunos parámetros que le vamos a pasar a nuestra acción personalizada:

Concretamente, le pasaremos el directorio donde se va a instalar la aplicación, el mapa del sitio de IIS, y el nombre del directorio virtual que el usuario indique en el wizard de instalación. Esta cadena es:
/targetdir=”[TARGETDIR]\” /targetvdir=”[TARGETVDIR]”
/targetsite=”[TARGETSITE]“
Luego, actualizamos nuestra clase de acción personalizada para que acceda a estos valores y haga algo con ellos como:
using System;
using 
System.Configuration;
using 
System.Configuration.Install;
using 
System.ComponentModel;
using 
System.Diagnostics;
using 
System.IO;namespace MyCustomAction
{
    [RunInstaller(
true)]
    
public class ScottSetupAction : Installer
    {

        public override void 
Install(System.Collections.IDictionary stateSaver)
        {
            
base.Install(stateSaver);            
// Retrieve configuration settings
            
string targetSite Context.Parameters["targetsite"];
            string 
targetVDir Context.Parameters["targetvdir"];
            string 
targetDirectory Context.Parameters["targetdir"];            if (targetSite == null)
                
throw new InstallException(“IIS Site Name Not Specified!”);            if 

(targetSite.StartsWith(“/LM/”))
                targetSite 
targetSite.Substring(4);            RegisterScriptMaps(targetSite, targetVDir);
        
}        
void RegisterScriptMaps(string targetSite, string targetVDir)
        {
            
// Calculate Windows path
            
string sysRoot System.Environment.GetEnvironmentVariable(“SystemRoot”);
            
// Launch aspnet_regiis.exe utility to configure mappings
            
ProcessStartInfo info = new ProcessStartInfo();
            
info.FileName Path.Combine(sysRoot, @”Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe”);
            
info.Arguments = string.Format(“-s {0}/ROOT/{1}”, targetSite, targetVDir);
            
info.CreateNoWindow = true;
            
info.UseShellExecute = false;            Process.Start(info);
        
}
    }
}

El código anterior lanza la utilidad aspnet_regiis.exe que viene con ASP.NET en el directorio \Windows\Microsoft.net\framework\v2.0.5.0727\, y le pasa el directorio en el que se va a instalar la aplicación, junto a la opción “-s” — que le indica que IIS que la versión de ASP.NET que se usará en esa aplicación es la 2.0, y no heredará la versión de ninguna aplicación padre.
Nota: Si estamos usando IIS 6 o 7, también querremos añadir alguna lógica a nuestra acción personalizada para asegurarnos que el pool de la aplicación que usará también será con la versión 2.0. También podemos decirle al administrador que compruebe manualmente eso después de instalar la aplicación.
7) Ejemplo de una acción personalizada útil:  Configurar la cadena de conexión a la base de datos.
En este ejemplo añadiremos alguna pantalla al instalador que permita al usuario configurar la cadena de conexión a la base de datos que usará la aplicación.
Clic derecho en el proyecto de instalación y abrimos las pantallas de la interfaz de usuario otra vez:

Clic derecho en el nodo “Instalar” en las pantallas de la interfaz de usuario y seleccionamos la de añadir un nuevo diálogo a la instalación del wizard:

Seleccionamos una de las pantallas TextBox para obtener los detalles de la cadena de conexión:

Clic derecho en el nodo de la pantalla TextBox y la movemos arriba (justo antes de que le digamos el sitio en el IIS y el nombre de la aplicación a usar):

Hacemos clic en la pantalla de TextBox y nos vamos a la ventana de propiedades. A traves de esta ventana podemos cambiar el texto que se mostrará en la pantalla, y también podemos controlar cuantos textboxs se van a ver:

Vemos que en la ventana de propiedades hemos puesto que los textboxs Edit2, Edit3 y Edit4 no son visibles. Ahora cuando compilemos y ejecutemos la instalación veremos este diálogo en los pasos del wizard:

Ahora que tenemos una interfaz para obtener la cadena de conexión, queremos asegurarnos de que se le pasa a nuestra clase de acción personalizada. Podemos hacer esto con un clic derecho en el proyecto de instalación web y seleccionando “View\Custom Actions” y abriendo la página de propiedades de nuestra acción personalizada:

Queremos actualizar la propiedad CustomActionData y ponerla en la cadena de conexión de la base de datos que usaremos (Pasaremos el valor del textbox EDITA1 en la ventana de la interfaz de usuario):
/targetdir=”[TARGETDIR]\” /db=”[EDITA1]” /targetvdir=”[TARGETVDIR]” /targetsite=”[TARGETSITE]“
Podemos actualizar nuestra acción personalizada para obtener y usar esta cadena de conexión para actualizar el archivo web.config de nuestra aplicación. Aquí tenéis un método que abre el archivo web.config y lo actualiza programáticamente con la cadena introducida por el usuario:
void ConfigureDatabase(string targetSite, string targetVDir, string connectionString)
{
    
// Retrieve ”Friendly Site Name” from IIS for TargetSite
    
DirectoryEntry entry = new DirectoryEntry(“IIS://LocalHost/” + targetSite);
    string 
friendlySiteName entry.Properties["ServerComment"].Value.ToString();    // Open Application’s Web.Config
    
Configuration config WebConfigurationManager.OpenWebConfiguration(“/” + targetVDir, friendlySiteName);    

// Add new connection string setting for web.config
    
ConnectionStringSettings appDatabase = new ConnectionStringSettings();
    
appDatabase.Name DATABASE_CONNECTION_KEY;
    
appDatabase.ConnectionString connectionString;     config.ConnectionStrings.ConnectionStrings.Clear();
    
config.ConnectionStrings.ConnectionStrings.Add(appDatabase);    // Persist web.config settings
    
config.Save();}

A partir de ahora, cuando ejecutemos el programa de instalación de el archivo web.config de nuestra aplicación web se actualizará con la cadena de conexión que le pongamos en la instalación.

4 comentarios:

  1. Muy buen comentario, la mejor explicación de como crear y manipular un proyecto de instalación que he visto, solo le añadiria una cosa: podemos agregar un new item -> Installer class y es todavia mas comodo crear el archivo para la custom action. Salu2

    ResponderEliminar
  2. Este comentario ha sido eliminado por un administrador del blog.

    ResponderEliminar
  3. Muy funcional y efectivo, muchas gracias !!

    ResponderEliminar
  4. Y como sería si quieres crear un instaldor Web, que reuna varios sitios web... digamos que quiero hacer un integrador de setups...

    gracias

    ResponderEliminar