“Enterprise Library 5.0” Lista para ser descargada

image 

Muy buenas a tod@s,

Ya está lista la Release de lla Entlib 5.0 para ser descargada.

  • Soporte para .Net Framework 4.0 e Integración en Visual Studio 2010
  • Integración con WPF
  • Consolas de configuración  de todos los tipos
    • Para 32 y 64 bits
    • Para 32 y 64 bits con el Framework 4.0
  • Y mucho más………….

Todo, desde aquí (EntLib 5.0).

Saludos y a disfrutarla, 😉
Juanlu

Compilando en 32 o en 64 bits

 

Últimamente me he encontrado con dudas y preguntas que se plantean algunos compañeros sobre la compilación en 64bits.  En ocasiones, me he encontrado cosas un poco “liososas” al respecto, pero,  sinceramente, despues de hacer un pequeño ejemplo para chequearlo, veo que no parece tan complicado, o al menos eso creo yo.

Veamos ese ejemplo “chorras” pero que una vez más nos da la solución a la duda

  • Crear una solución Visual Studio “Basic Deploy x32 x64”
  • Añadir un proyecto de tipo Consola
  • Añadir otro proyecto de tipo “Setup” según se muestra en la siguiente figura:

image

  • Ahora nuestra solución quedará de la siguiente manera:

image

  • Lo siguiente es crear una nueva plataforma de compilación “x64” tal y como sigue:
    • Hacer click sobre la solución y seleccionar “Configuration Manager…

          image

  •  
    • A continuación podemos eligir entre copiar la configuración de una plataforma ya existente o vacía (“<Empty>”). La ventaja de utilizar una existente (x86, que siempre está present), tenemos la ventaja de que las opciones de compilación para “Debug” y “Release” están listas. 

          image

  • Ahora ya está todo listo, ajustamos la configuración; “Debug” y “Release” si no lo hemos hecho en el paso anterior, es decir en caso de haber creado la plataforma a partir de una vacía. Para ello tendremos que seleccionar en cada proyecto y para cada uno de los tipos de configuración si queremos marcar, “DEBUG”, “TRACE”, etc… Entre otras cosas, es posible que nos interese cambiar el “Output path”, sino, por defecto la compilación en 32 bits se realizará en “bindebug” y  la de 64 en “binx64debug”.
  • Si ejecutamos el proyecto en 32 bits y observamos el c podemos observar como las Dlls utilizadas; Sytem.Core, System.Data, etc son las de 32 bits.

image

  • Sin embargo, si ejecutamos la aplicación en 64bits y volvermos a observar el “Process Exprorer”, vemos como las DLLs utilizadas son las de 64 bits.

image

Llegado este momento el proyecto compila y se ejecuta en 32 y 64 bits. Es en momento de ver como se comporta el proyecto de SETUP:

Entre las propieades del proyecto de setup tenemos la propiedad “TargetPlatform” que tendremos que cambiar según la compilación que queramos hacer; para 32 o para 64 bits.

image

Hasta aquí, el caso fácil y prácticamente todo automático, pero, siempre existen algunas excepciones o “complicaciones” a tener en cuenta:

  • ¿Que pasa si tengo que trabajar con directorios específicos de 64bits; “ProgramFiles64Folder”, “CommonFiles64Folder” o, para el caso de 32 bits “ProgramFilesFolder”, “CommonFilesfolder”, etc.? En este caso sólo se podrá trabajar con una plataforma específica, y es posible que tengamos que crear dos proyectos de Setup, uno para 32 y otro para 64.
  • Pero, ¿Y si tenemos mucha lógica en el setup; nuevos formularios, custom actions, etc? La idea es intentar evitar dependencias de cada plataforma. Desde mi punto de vista lo mejor es lanzar el .MSI desde un .BAT o .VBS pasando el parámetro “TARGETDIR”.  En cuanto a otros directorios o depencias,  lo mejor es trabajar con “custom actions” creando la lógica adecuada, pero de esta manera siempre un único Setup y sólo cambiando la propiead “TargetPlatform”. Para más detalle sobre todo esto, hechad un vistazo a mi anterior post; “Como hacer un setup en 15 min”.
  • ¿Que ocurre si nuestro proyecto de 64 bits trabaja con DLLs concretas de terceros?¿Que ocurre con las referencias? Una buena idea puede ser; crear un nuevo proyecto vacío (sin ninguna clase) en el mismo directorio del proyecto de 32 bits, de manera que ambos proyectos lo compartan todo.  Es decir, tendríamos en un mismo directorio dos ficheros “.csproj”. Bastará incluir las referencias por separado en cada uno de los proyectos y en algún caso, alguna directiva de compilación. En este caso nos tocará crear dos proyectos de Setup. ¡intentemos unificar toda la logica!.

Estos úiltimos puntos dependerán de la complejidad que tenga nuestro Setup.  La cuestión es, complicarse cuanto menos, mejor.    El principio KISS, siempre presente.

Saludos
Juanlu

Como hacer un setup personalizado en 15min con Visual Studio .NET

Muy buenas de nuevo, (y nunca mejor dicho lo de “nuevo”).

Llevo ya un tiempo sin aparecer por aquí, y la verdad, es que desde entonces no han dejado de aparecer novedades.  Me siento como un niño pequeño que quiere jugar con sus nuevos juguetitos y, de alguna manera “no le dejan”, en fin….. Ya os contaré algunas cosas poco a poco.

En un intento de retomar mi aparición por aqui, os muestro a continuación y un pequeño artículo sobre la generación de Setup personalizados que escribí hace poco. A ver si os sirve:

Hace ya un tiempo quería comentar la facilidad de .net para la generación de setup’s personalizados y sobre todo como encaminarlos a la distribución vía SCCM (el antiguo SMS) o incluso, como sustitución a la generación de diferentes ficheros de configuración para nuestros “famosos” y diferentes entornos; desarrollo, integración y producción.

  • ¿Por qué copiar de acá para allá diferentes ficheros de configuración que cambian de un día para otro?
  • ¿No es mejor disponer de un mismo fichero de configuración y no compilar nada para el paso entre entornos?

Vamos a seguir detalladamente los pasos adecuados a partir de un sencillo ejemplo que consiste en un formulario Windows que utiliza un texto fijo recuperado del fichero de configuración y que podría ser cualquiera de nuestros proyectos actuales

1. Añadimos a la solución existente un proyecto de tipo “Setup and Deployment” con el nombre <NombreProyecto>Setup:

clip_image002

2. Añadimos un nuevo proyecto de tipo “Class library” y denominarlo por ejemplo, <NombreProyecto>CustomInstall:

clip_image004

3. Añadimos una nueva clase “CustomParameters.cs” o renombrar la clase “Class1.cs” generada por defecto con la siguiente información:

using System.Collections;
using System.Configuration.Install;

namespace DeployEn15MinCustomInstall
{
    public class CustomParameters
    {               
        private static System.Collections.IDictionary state = null;
        public static string PREFIJO_SALUDO = "PrefijoSaludo";
        
        private string _prefijoSaludo;        

        /// <summary>
        /// Constructor para los instalables sin parametros de entrada
        /// </summary>
        /// <param name="savedState"></param>
        public CustomParameters(IDictionary savedState)
        {
            state = savedState;
        }

        public string PrefijoSaludo
        {
            get { return _prefijoSaludo; }
            set { _prefijoSaludo = value; }
        }

        /// <summary>
        /// Recupera los parametros pasados al msi.
        /// </summary>
        /// <param name="installContext"></param>
        public void LoadContext(InstallContext installContext)
        {
            this.PrefijoSaludo = installContext.Parameters[PREFIJO_SALUDO];          
        }
    }
}

Donde; la constante “PREFIJO_SALUDO”, el atributo y la propiedad “PrefijoSaludo” serán sustituidos por cuantos parámetros sean necesarios pasar al ”.msi” para la instalación.

4. Añadimos una nueva clase “ConfigManager” con objeto de manejar la sección de “AppSettings” del fichero de configuración de la aplicación y poder añadir así nuevos valores a las key’s ya existentes.

public class ConfigManager
    {
        #region Attributos

        private string _ConfigPath;
        private Configuration _Config;
        private AppSettingsSection _AppSettings;

        #endregion

        /// <summary>
        /// Inicializa una nueva instancia de la clase<see cref="ConfigUpdater"/>.
        /// </summary>
        /// <param name="configPath">The config path.</param>
        public ConfigManager(string configPath)
        {
            _ConfigPath = (configPath == null ? String.Empty : configPath);

            try
            {
                _Config = ConfigurationManager.OpenExeConfiguration(_ConfigPath);
                _AppSettings = _Config.AppSettings;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(
                    String.Format("Error adding new configuration parameters into: '{0}'.{1}{2}",
                    _ConfigPath, ex.Message, ex.StackTrace));
            }
        }

        /// <summary>
        /// Añade una nueva clave (keyName) a la sección "appSettings"
        /// del fichero de configuración con un valor (value).
        /// </summary>
        /// <param name="keyName">Nombre de la clave a añadir.</param>
        /// <param name="value">Valor a asignar a la nueva clave.</param>
        public void AddParam(string keyName, string value)
        {
            if (_AppSettings.Settings[keyName] == null)
                _AppSettings.Settings.Add(keyName, value);
        }

        /// <summary>
        /// Elimina del fichero de configuración una clave (keyName) de la sección "appSettings"
        /// del fichero de configuración.
        /// </summary>
        /// <param name="keyName">Nombre de la clave a eliminar..</param>
        public void RemoveParam(string keyName)
        {
            _AppSettings.Settings.Remove(keyName);
        }

        /// <summary>
        /// Modifica o añade una clave (keyName) de la sección "appSettings".
        /// </summary>
        /// <param name="keyName">Nombre de la clare a añadir o modificar.</param>
        /// <param name="value">Valor a asignar a la clave</param>
        public void SaveParam(string keyName, string value)
        {
            if (_AppSettings.Settings[keyName] != null)
                _AppSettings.Settings[keyName].Value = value;
            else
                AddParam(keyName, value);
        }

        /// <summary>
        /// Guarda el fichero de configuración con los cambios realizados
        /// en la sección "appSetting".
        /// </summary>
        public void Save()
        {
            if (!_AppSettings.ElementInformation.IsLocked)
                _Config.Save();
            else
                throw new ApplicationException("Section was locked, could not update");
        }
    }

5. Añadimos al proyecto “CustomIntall” un nuevo ítem de tipo “Installer Class” y lo denominamos por ejemplo “CustomActions.cs”.

clip_image006

El contenido de este fichero será:

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace DeployEn15MinCustomInstall
{
    [RunInstaller(true)]
    public partial class CustomActions : Installer
    {
        private const string PAREMETER_NOT_SPECIFIED = "El parámetro de instalación '{0}' no ha sido especificado. La instalación será cancelada.";

        private CustomParameters _parameters = null;        

        // Añadir al array todos los parámetros requeridos durante la instalación.
        // Dejarlo vacío sino hay parámetros requeridos.
        private ArrayList requiredParameters = new ArrayList { CustomParameters.PREFIJO_SALUDO };

        public CustomActions()
        {
            InitializeComponent();
        }


        public override void Install(System.Collections.IDictionary stateSaver)
        {
#if DEBUG
            Debugger.Launch();
#endif

            base.Install(stateSaver);

            // Si la instalación es ejectuada previo paso de parámetros.
            if (this.Context != null && this.Context.Parameters.Count > 0)
            {
                _parameters = new CustomParameters(stateSaver);
                _parameters.LoadContext(this.Context);

                ConfigureFileConfig();
            }
        }

        private void ConfigureFileConfig()
        {
            string assemblyPath = this.Context.Parameters["assemblyPath"];
            string fileName = Path.GetFileNameWithoutExtension(assemblyPath).Replace("CustomInstall", ".exe");

            string exeConfigPath = Path.Combine(Directory.GetParent(assemblyPath).FullName, fileName);

            ConfigManager config = new ConfigManager(exeConfigPath);

            this.UpdateAppSettings(config);

            // Si todo es correcto se realiza el commit del fichero de configuración.
            config.Save();

            config = null;
        }

        private void UpdateAppSettings(ConfigManager config)
        {
            PropertyInfo[] props = _parameters.GetType().GetProperties();

            foreach (PropertyInfo prop in props)
            {
                string propValue = prop.GetValue(_parameters, null) as string;
                if (!String.IsNullOrEmpty(propValue))
                {
                    config.SaveParam(prop.Name, propValue);
                }
                else
                {
                    // Parámetro requerido no especificado
                    if (requiredParameters.Contains(prop.Name))
                    {
                        throw new InstallException(
                            String.Format(PAREMETER_NOT_SPECIFIED, prop.Name));
                    }
                }
            }
        }

    }
}
Las siguientes instrucciones 

Las siguientes instrucciones van a permitir realizar una parada en tiempo de depuración con objeto de facilitar dicha labor. Esta instrucción tendrá más sentido cuando el ejecutable no se inicie directamente desde el Visual Studio.

#if DEBUG
            Debugger.Launch();
#endif

6. Añadimos al proyecto de Setup dos items del tipo, “Primary Output”;

  • “DeployEn15Min”(Ejecutable Windows Form) y,
  • “DeployEn15MinCustomInstall”(Class Library que contiene el “Installer class”) .

clip_image008

7. Finalizado el paso anterior, nuestra solución tendrá la siguiente apariencia además de proyecto de Test correspondiente (como en cualquier proyecto debemos tener siempre):

clip_image010

8. A continuación seleccionamos el proyecto “DeployEn15MinSetup” y hacemos click en el icono de “Custom Actions”.

9. Sobre la carpeta “Install” de las Custom Actions, hamemos click derecho y seleccionamos del “Application Folder” el “Primary output” referente al “CustomInstall”.

clip_image012

10. Generamos un fichero de comandos “.bat” con la siguiente instrucción y lo ejecutamos en la misma carpeta en donde se encuentre el Setup:

msiexec /l* “DeployEn15Min.log” /i DeployEn15MinSetup.msi TARGETDIR=”C:Test” allUsers=[ALLUSERS] PREFIJOSALUDO=”Deploy en 15 minutos v1.1″

Ahora, el ejecutable recibe los parámetros pasados en el comando. Los que se muestran durante la instalación son parámetros estándares, sin embargo, si después de la instalación comprobamos el fichero de configuración resultante, veremos como el valor de la key “PrefijoSaludo” del “appSettings”, ha cambiado por el nuevo valor.

clip_image014

Es en este punto, donde cobra fuerza la instrucción, “Debugger.Launch();” antes comentada.

Para conseguir la modificación de todos nuestros parámetros de configuración durante la instalación, tendremos que añadir valores a la propiedad “CustomActionData” del Custom Action “Install” tal y como se indica en la siguiente figura para nuestro parámetro “PrefijoSaludo”:

clip_image016

Se añadirán tantos valores como parámetros sean susceptibles de recuperar en tiempo de instalación.

Los “custom actions”; “Commit”, “Rollback” y “Uninstall”, serán implementados de la misma manera siempre y cuando en nuestra clase DeployEn15MinCustomInstall.CustomInstall.cs sobrescribamos los métodos correspondientes. Adicionalmente podrán sobrescribirse otros métodos que ocurren antes o después de estas acciones, con lo que tendremos mayor control sobre cualquier “cosa” que queramos realizar durante y después de la instalación.

El comando “msiexec” recibe un parámetro /l* que permite indicar un fichero de log en el que se registrarán todos pasos generados durante la instalación. Su objetivo, detectar cualquier posible error durante dicho proceso.

Nota: Con objeto de mejorar la instalación de prerrequisitos, actualizaciones, parches etc. de nuestra aplicación, podemos utilizar un “.vbs” (Visual Basic Script) en lugar de un “.bat”, permitiendo de esta manera mayor control; acceso al registro de Windows, etc. El objetivo de esto es permitir a los administradores de sistemas las modificaciones adecuadas según las necesidades concretas de la distribución. Un ejemplo claro podría ser, comprobar una clave del registro de Windows para verificar la existencia de otro programa o prerrequisito, de una versión anterior, etc.

 Un saludo desde mi “nueva casa”

Juanlu, El Guerre