[ASP.NET/IIS] Compartir las variables de session entre diferentes App con modo StateServer (modificando el AppDomainAppId)

Esta es una articulo que se corresponde con uno anterior donde hable sobre las opciones de compartir session:

Particularmente en este articulo veremos la opción 1.1

OPCION 1: Cambiar el modo de estado de session (SessionState) a StateServer

OPCION 1.1: O cambiamos el ID de App (AppDomainAppId)

OPCION 1.2: O cambiamos el método que se obtiene el ID de Session (sessionIDManagerType)

Si bien hay varias opciones para compartir, la idea de hacerlo con el Servicio de estado de ASP.NET (StateServer) pero no tiene en modo nativo la forma de unificar el nombre de la aplicación y mas precisamente la propiedad AppDomainAppId que se utiliza dentro del servicio de estado para mantener el diccionario de variables de session por aplicación. Además mas abajo un ejemplo para descargar

 

Vamos paso por paso

Pasos que debemos cumplir para lograr el objetivo

  1. Todas las aplicaciones deben estar bajo el mismo dominio (para restricciones de cookie) IMPORTANTE!
    En este caso mis pruebas fueron bajo localhost, pero funciona si cambas el dominio. Solo respetar que cada app esta bajo el mismo dominio
  2. Establecer el SessionState en modo StateServer
  3. Configurar el servicio de estado de session (Importante)
  4. Establecer la misma machinekey
    Incluso para compartir entre diferentes servidores cuando estas en un cluster
    Ejemplo: Puedes encontrar varios generadores online
  5. Establecer la misma nombre de la cookie
    PAra poder compartir los datos deben ser ubicados (en la misma cookie de session). Acuerdense que es simplemente un identificador
  6. IMPORTANTE El mismo nombre de la app (mmmm!??) propiedad AppDomainAppId
    Por lo que hice este post donde explicamos como modificarla

 

Paso 1: Todas las aplicaciones deben estar bajo el mismo dominio

Aclaraciones, bajo el mismo dominio, y están configuradas como directorios virtuales. (mas abajo el ejemplo para descargar)

image

Para crear una de estas app

SNAGHTMLc52d597

image

Mas adelante veremos como se obtiene el nombre de la app AppDomainAppId (Paso 6)

Paso 2: Establecer el SessionState en modo StateServer

Aqui utilizamos la seccion del web.config sessionState para establecer donde se ubicara nuestra variables de session

<sessionState cookieName="YODADemoApp" 
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />

Aqui el primer comentario es que no tiene una forma de setear el nombre de la aplicación, siendo que en su correspondiente funcionalidad en Windows Azure si tiene! Sorpresa vamooosss que se puede modificar applicationName

http://msdn.microsoft.com/en-us/library/windowsazure/gg185682.aspx

 

PASO 3: Configurar el servicio de estado de sesión

Para que funcione al configuración del Paso 3 donde establecimos el modo StateServer y la ubicacion del servidor en la maquina local debemos habilitar ese servicio

SNAGHTMLc29ee92

 

Paso 4: Establecer la misma machinekey

Incluso para compartir entre diferentes servidores cuando estas en un cluster o en la misma maquina debes configurar la misma machinekey que se utiliza para:

“(…)Configura los algoritmos y las claves que se utilizan en el cifrado, descifrado y validación de los datos de autenticación de formularios y de los datos de estado de vista, así como para la identificación del estado de sesión fuera de proceso.(…)”

Ejemplo: Puedes encontrar varios generadores online

 

Paso 5: Establecer la misma nombre de la cookie

PAra que se guarde el valor de la session (un indentificdor) y que podamos obtenerlo a traves de multiples applicaciones en necesario que el nombre sea identico, por esta razon es conveniente modificarlo en la propiedad cookieName de sessionState

<sessionState cookieName="YODADemoApp" 
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />

 

Paso 6: IMPORTANTE El mismo nombre de la app (mmmm!??)

Bueno hicimos todo lo anterior, pero cuando utilizamos StateServer para guardar los datos de session el proveedor utiliza el ApplicationName. El servicio es simplemente un ejecutable que tiene en cuenta el nombre de la aplicación

SNAGHTMLc3d7722

 

Como unificar el mismo nombre de ApplicationName para guardar el estado de session

Por aquí podemos leer que los proveedores de utilizan el nombre de la app para mantener el estado de session:

(…) Para mantener el ámbito de la sesión, los proveedores de estados de sesión guardan por separado la información de sesión de cada aplicación. De esta forma, varias aplicaciones ASP.NET pueden usar el mismo origen de datos sin entrar en conflicto en caso de que se encuentren identificadores de sesión duplicados.

Dado que los proveedores de almacén de estados de sesión guardan por separado la información de sesión de cada aplicación, deberá asegurarse de que el esquema de datos, las consultas y las actualizaciones incluyen el nombre de la aplicación. Por ejemplo, se podría utilizar el comando siguiente para recuperar los datos de sesión de una base de datos.(…)

 

Cual es el nombre de mis app en este ejemplo

Las app que configure bajo el WebSite0 (dos websites ASP.NET Webforms y un app con ASP.NET MVC)

SNAGHTMLbdfcdb8

El árbol en el IIS quedo así en el ejemplo:

Para las app Los AppDomainAppId son respectivamente
image
WebSite0:

/LM/W3SVC/2/ROOT

WebSite1:

/LM/W3SVC/2/ROOT/WebSite1

WebSite2:

/LM/W3SVC/2/ROOT/WebSite2

MvcApplication1:

/LM/W3SVC/2/ROOT/MvcApplication1

De donde sale este nombre?

Podes listar las app con la herramienta de lista de comandos appcmd pero los AppDomainAppId no se encuentran visible

Comando: appcmd list app

SNAGHTMLbe61024

Pero ni aquí encontré el AppDomainAppId

SNAGHTMLbefffcf

Pero si listamos la configuración por sitio podemos ver el ID del sitio (un numero), con appcmd:

SNAGHTMLc014854

En la configuración avanzada mediante el Administrador de IIS

SNAGHTMLc033947

Entonces… como se arma el nombre?

El primer sitio que esta detenido “Default Web Site” es el primero que se creo en mi IIS local es el sitio numero 1, el segundo que cree para esta demo es WebSite0 que como es el 2 y el el raiz tiene el nombre:

/LM/W3SVC/2/ROOT

Por eso los nombres: /LM/W3SVC/2/ROOT/{nombre de la app}

 

 

Cambiar el AppDomainAppId

Primero antes de cambiarlo como lo leemos desde nuestro código:

Por eso veras en que el ejemplo que lo colocamos al nombre en un webcontrol literal llamado litAppDomainAppId:

private void RefrescarControles()

    {

        litAppDomainAppId.Text = HttpRuntime.AppDomainAppId;

 

        Literal1.Text = SessionHelper.Variable1;

        Literal2.Text = SessionHelper.Variable2;

    }

Como cambiar

Si vemos la propiedad es estática y de solo lectura, así que no nos sirve ya que no podremos modificarla

Aquí nos ayudamos Reflection para obtener la variable privada dentro de HttRuntime que contiene el valor que es expuesto a traves de la propiedad AppDomainAppId. Ya han publicados ejemplos aquí y aquí, pero bueno es Reflection al fin y al cabo

El ejemplo seria en una método estático que nos ayude a modificar el nombre:

public static class SessionStateServerSharedHelper
{
public static void ChangeAppDomainAppId(string name)
{
FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
if (runtimeInfo == null) return;
HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
if (theRuntime == null) return;
FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);
if (appNameInfo == null) return;
var appName = (String)appNameInfo.GetValue(theRuntime);
if (appName != "applicationName") appNameInfo.SetValue(theRuntime, name);
}
}
 
En el global.asax nos ayudamos con el evento Application_Start (que se ejecuta una sola vez al primera vez que se solicita un recurso a la aplicacion web ASP.NET)
void Application_Start(object sender, EventArgs e) 
{
// Code that runs on application startup
SessionStateServerSharedHelper.ChangeAppDomainAppId("YODADemoApp");
}

Con esto logramos que nuestras aplicaciones donde aplicamos esto tengan el mismo nombre y asi poder compartir las variables de session cuando utilizamos ASP.NET State Server
 

NOTA 1: El único problema que podemos encontrar es cuando los chicos de IT están monitoreando nuestros sitios y necesitan conocer en que app causo el problema, pero bueno hablando con ellos podremos detectarla con al nombre y la url que dio el error

NOTA 2: Cambiar metadata del IIS para unificar directorios: Si bien hay una forma de cambiar la metada es mas bien para compartir entre sitios web (aqui la idea que es que se mantenga la metadata y a nivel de aplicacion

 

El ejemplo para descargar

Sencillo para observar los pasos comentados. Se puede mejorar encapsulando este comportamiento y no estar compartiendo archivos de clase (eso lo dejo para mejorar por el que necesita utilizarlo). Lo puedes descargar directamente aquí

   
Tres aplicaciones bajo un solo dominio

2 Websites ASP.NET Webforms

1 Webapp ASP.NET MVC

Debes configurarlo en el IIS como aplicaciones

image
Donde el negocio es simplemente modificar variables de session y ver los valores de todas las variables

Website1: Modifica la variable 1, Visualiza ambas variables

WebSite2: Modifica la variable 2

, Visualiza ambas variables

MvcApplication1: Visualiza ambas variables

SNAGHTMLc6dd182
Todas tienen una clase que nos ayuda a modificar el nombre de AppDomainAppId mediante Reflection Clase SessionStateServerSharedHelper

Metodo de clase (estatico): ChangeAppDomainAppId


Además nos ayudamos para tener intellisense en las variables de session con una clase.

Por ejemplo para obtner el valor de la Variable1 de session utilizo

public static string Variable1
{
get
{
if (HttpContext.Current.Session["Variable1"] != null)
{
return HttpContext.Current.Session["Variable1"].ToString();
}

return string.Empty;
}
set {
HttpContext.Current.Session["Variable1"] = value;
}
}

Una mejora es que el nombre de la AppDomainAppId compartida sea configurada por el AppSettings pero como se mencione mas arriba deberías reiniciar la app para que lo tome. Esto se puede solventar con la opcion 1.2 sessionIDManagerType que será para el próximo post

 

 

Espero que les sirva de ayuda o guía.

 

Delicious tags : , , , , ,

,