martes, 20 de diciembre de 2016

Dominio de aplicacion

Creo que una de las característica más desconocidas de .Net son los dominios de aplicación. Y en la practica lo estamos utilizando constantemente. Se trata de una característica que proporciona una capa de aislamiento dentro de un proceso. Todo lo que en realidad se piensa que es por proceso (variables estáticas, ...) en realidad es por dominio de aplicación.

Esta característica es muy útil para crear:
  • Plugins: pudiendo cargar ensamblados en tiempo de ejecución, sin que este afecte al resto de la aplicación.
  • Seguridad: Nos permite ejecutar conjuntos de código en un nivel de confianza específico.
  • Aislamiento: Puedes ejecutar diferentes versiones de un ensamblado en el mismo proceso.
  • Control de fugas de memoria: Si tenemos un proceso que consume gran cantidad de memoria y el recolector de basura no es capaz de liberarla, una solución es hacer correr el proceso en un dominio de aplicación diferente, y al destruir el dominio de aplicación se liberará toda la memoria que utilizaba.
  • Modificar ensamblados en tiempo de ejecución: Con esta característica es posible modificar los ficheros de ensamblado en tiempo de ejecución.
Un entorno en el que se utilizan los dominios de aplicaciones es en las aplicaciones asp.net, cuando montamos varios sites en el mismo proceso, lo que hace el IIS es crear un dominio de aplicación por cada aplicación asp.net

Para controlar un dominio de aplicación se utiliza la clase AppDomain, la cual nos permite conocer propiedades del dominio actual con AppDomain.CurrentDomain.


AppDomain miDominio = AppDomain.CurrentDomain;

O crear y destruir otros dominios de aplicación.


AppDomain miDominio = AppDomain.CreateDomain("NuevoDominio");
Con las diferentes sobrecargas del método CreateDomain se pueden definir criterios de seguridad, directorio de trabajo del nuevo dominio de aplicación, definir si se puede modificar los ficheros del ensamblado en tiempo de ejecución, ...

Una vez creado el nuevo dominio, lo siguiente que hay que hacer notar es que para comunicarse entre diferentes dominios de aplicación alojados en un mismo proceso hay que utilizar remoting. Por ello definiremos una clase de entrada que herede de MarshalByRefObject. Con un método que nos servirá de punto de entrada.

public class MiControladorDominio : MarshalByRefObject
{
    public void Inicio(int id)
    {
              
    }
}

Ahora tenemos que crear una instancia de nuestra clase controlador en el nuevo dominio.


MiControladorDominio controlador = (MiControladorDominio)miDominio.CreateInstanceAndUnwrap(
                typeof(MiControladorDominio).Assembly.FullName,
                typeof(MiControladorDominio).FullName);

Y ya podemos comunicar los dos dominios de aplicación mediante la instancia de la clase MiControladorDominio llamando al método publico de inicio. Recordando que la comunicación se hace a traves de remoting, con lo que todos los objetos de ida y vuelta serán serializados.

controlador.Inicio(55);

Cuando terminemos de utilizar el nuevo dominio, lo podemos destruir mediante el método Unload, liberando todos los recursos que ha utilizado el nuevo dominio.

AppDomain.Unload(miDominio);
La utilización de dominios de aplicación no es algo muy utilizado, principalmente, por su complejidad. Pero en ocasiones resuelve problemas que de otra manera seria más difícil de solucionar.

domingo, 4 de diciembre de 2016

Personalizar esqema de configuración en .Net (I)


Todo el mundo que ha trabajado con una aplicación .Net conoce el archivo Web.config o sus homólogos para aplicaciones de escritorio App.config (qué visual studio traduco con el nombre ejecutable.config) Y es muy habitual utilizar la clase AppSettings para definir los parámetros de configuración de la forma.
<appSettings>
    <add key="Setting1" value="May 5, 2017"/>
    <add key="Setting2" value="May 6, 2017"/>
</appSettings>

Pero en ocasiones necesitamos estructuras de datos más complejas o simplemente darle un aspecto más profesional. Y para ello existe la clase ConfigurationSection con la cual podemos definir una sección entera del archivo web.config.

Primero definimos nuestra clase de configuración. Utilizando un patrón Singleton para ofrecer una instancia única.

public sealed class MyConfigurationSection : ConfigurationSection
{
    #region Singleton
    private MyConfigurationSection()
    {
    }

    private static MyConfigurationSection _CurrentConfiguration;

    public static new MyConfigurationSection CurrentConfiguration
    {
        get
        {
            if (_CurrentConfiguration == null)
            {
                _CurrentConfiguration = (MyConfigurationSection)ConfigurationManager.GetSection(@"myConfig");
            }

            return _CurrentConfiguration;
        }
    }
    #endregion
}

Y posteriormente definimos los parámetros de configuración que formaran parte de nuestra sección.


[ConfigurationProperty("serverUrl", IsRequired = false)]
public string ServerUrl
{
    get { return (string)this["serverUrl"];
    set { this["serverUrl"] = value; }
}

Pudiendo definir si el campo es obligatorio o no, definiendo un valor por defecto.


[ConfigurationProperty("MaxUsers", IsRequired = false, DefaultValue =25)]

public long MaxUsers

{

    get { return (long)this["maxUsers"]; }

    set { this["maxUsers"] = value; }

}

Definir un valor máximo.


[LongValidator(MinValue = 1, MaxValue = 1000000, ExcludeRange = false)]


[ConfigurationProperty("MaxUsers", IsRequired = false, DefaultValue =25)]


public long MaxUsers


{


    get { return (long)this["maxUsers"]; }


    set { this["maxUsers"] = value; }

}

O especificar un tamaño de la cadena o una lista de caracteres invadidos.

[StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"|\\", MinLength = 1, MaxLength = 60)]

[ConfigurationProperty("FileName", IsRequired = true)]

public string FileName

{

    get { return (string)this["fileName"]; }

    set { this["fileName"] = value; }
}


Una vez tenemos nuestra clase para leer el fichero de configuración, deberemos introducir la configuración en nuestro fichero web.config o app.config, según proceda. De la siguiente forma.

Primero definimos la referencia a nuestra sección

<?xml version="1.0"?>
<configuration>
  <configSections>
   <section name="myConfiguration" type="namespace.MyServerConfiguration, Assembly" />
  </configSections>
….
</configuration>

Y ya podemos definir nuestra sección.

<myConfiguration serverUrl="http:// …." MaxUsers="48">