Utilizar REDIS como proveedor de estado de sesión (y balanceo)

Hola, en este artículo vamos a ver como almacenar el estado de sesión de ASP.NET en REDIS, pudiendo servir para escalamiento horizontal de nuestra solución, al contrario de InProc que almacena los datos de la sesión en memoria del mismo servidor web.

Redis es un motor de base de datos en memoria, basado en el almacenamiento en tablas de hashes (clave/valor) pero que opcionalmente puede ser usada como una base de datos durable o persistente. Está escrito en ANSI C por Salvatore Sanfilippo quien es patrocinado por VMware.1 2 y está liberado bajo licencia BSD por lo que es considerado software de código abierto.

REDIS se comporta bastante bien  como almacén de sesiones, de hecho puedes ver una buena presentación sobre esto

Si ahora estas convencido, vamos a hacer el primer paso, que es descargar REDIS para Windows de la siguiente URL:

https://github.com/rgl/redis/downloads

Siguiente, siguientes… y listo, luego en c:

image

Luego verás REDIS instalado en c:Program FilesRedis

image

Puedes cambiar la configuración dentro de la carpeta conf en el archivo redis.conf, como puerto, contraseñas y mucho más.

Ahora debes correr el servicio con redis-server.exe

image

Luego vamos a utilizar el proyecto que está en la siguiente URL http://chadmeyercodez.wordpress.com/2012/07/06/redis-session-state-provider-for-asp-net/

En donde se dieron el trabajo de programar el proveedor de sesión y tambien de roles y membership, aunque nosotros para este ejemplo solo veremos el tema de la sesión. Puedes descargar el proyecto con todos los proveedores desde acá:

https://dl.dropboxusercontent.com/u/1303802/AspNetRedisProviders-master.zip

Nota: este proyecto no me pertenece, aunque es público.
Esta es la estructura del proyecto, en mi caso voy a extraer lo que necesito, para efectos de simplificar la solución:

image

Pd: esta solución utiliza BookSleeve como cliente de REDIS, si quieres puedes instalarlo desde Nuget http://www.nuget.org/packages/BookSleeve/

PM> Install-Package BookSleeve

Y bueno, ahora nuestro proyecto, voy a crear uno desde cero e ir incluyendo lo que necesitamos, mi proyecto va a ser mega simple , la gráfica es la siguiente:

image

La funcionalidad es mínima, lo que nos interesa es que funcione bien el almacenamiento de estado de sesión y además el compartir las sesiones en una granja de servidores, simuladas por dos sitios web en mi misma máquina, los cuales no comparten app pool, pero deben compartir sesiones, de manera de que si un sitio cae, siga funcionando sin problemas las sesiones en el otro sitio, básicamente es lo siguiente:

image

Veamos el código asociado a la pantalla, es casi cero:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace RedisDemo

{

    public partial class _Default : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            if (!Page.IsPostBack)

            {

                lb_session.Text =Convert.ToString(Session["test"]);

            }

        }

 

        protected void Button1_Click(object sender, EventArgs e)

        {

            Session["test"] = TxSession.Text;

        }

    }

}

Como ves, lo único que hace es setear la sesión y cuando se carga por primera vez la página, o si quieres,  cuando no hace postback, obtiene el valor de la sesión.

Se debe agregar la siguiente línea al web.config dentro de system.web para indicar el nuevo proveedor de estado de sessión

<sessionState mode="Custom" customProvider="RedisSessionProvider">

<providers>

<add name="RedisSessionProvider"
      type
="RedisProviders.RedisSessionStateStoreProvider, RedisProviders"
/>

</providers>

</sessionState>

Para este demo, mi configuración del IIS tengo lo siguiente:

image

Dos sitios web con la misma aplicación, Sitio 1 en el puerto 8080 y Sitio 2 en el puerto 8081:

image

Ahora seteo en Sitio 1 la sesión con el valor “Probando” y …

image

Al refrescar sitio 2 ya tiene el valor de la sesión Sonrisa, excelente!! Risa  al parar el sitio1 image

Volvemos a subir el sitio 1 y la sesión todavía existe Sonrisa, no se pierde:

image

Muy cool!, te dejo el código para que puedas probarlo:

DESCARGAR

Invitación a Charla : Microsoft ASP.NET SignalR: La Web en Tiempo Real Simplificada

SignalR Logo

Hola!, los quería invitar a este webcast que voy en donde vamos a hablar desde la teoría hasta la práctica sobre signalR de manera que puedas fácilmente incorporar esta biblioteca que nos permite crear Web con comportamiento en tiempo real con un esfuerzo mínimo! SignalR se preocupará de las capacidades del browser para lograr la comunicación!!, bueno hay varias características muy cool que podemos revisar.

Cuando?

Inicio: martes, 25 de febrero de 2014.
Zona horaria: (GMT-05:00) Bogotá – 13:00 horas /Chile 15:00 horas
Duración: 1 hora(s)

Regístrate acá:

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032577901&Culture=es-AR&community=0

Que NO hacer con ASP.NET

Estas son buenas prácticas que están extraídas de http://www.asp.net/aspnet/overview/web-development-best-practices/what-not-to-do-in-aspnet,-and-what-to-do-instead y encontré interesante traducirlas. Quizás alguien podría decir “lo primero que debes hacer con ASP.NET es no programar con WebForms”, y puede tener razón a esta altura del partido, pero si ya tienes apps con WebForms y te es imposible migrarlas, (por esfuerzo, tiempo, etc), entonces sería bueno que hicieras un checklist de lo siguiente:

Control Adapters

Recomendación: Deja de utilizar control adapters para el render adaptativo y comienza a usar CSS media queries y código estándar HTML. Los control adapters aparecieron en NET 2.9 para hacer render para diferentes dispositivos y entornos. Ahora, este render adaptativo puede ser construido con CSS y HTML. Asi que, deja de usarlos Sonrisa

Para mayor información, revisa info de Media Queries y How To: Add Mobile Pages to Your ASP.NET Web Forms / MVC Application.

Estilos en los Controles

Recomendación: Ya no más!, no debemos setear los estilos en el markup del control, por el contrario, se deben asignar los estilos en sus correspondientes CSS.

Si bien los webcontrols contienen ciertas propiedades que pueden ser usadas para setear estilos “in-line” , por ejemplo , la propiedad Forecolor, que setea el color del texto de un control, podemos lograr este mismo efecto de manera mucho más efectiva a través de las hojas de estilo, las cuales permiten centralizar los valores de los estilos y evitamos el “desorden” de asignar todo in-line.

Control Callbacks

Recomendación: Dejar de utilizar los control callbacks, y en lugar utilizar Ajax, UpdatePanel (peligro!) métodos de acción MVC , Web API o SignalR.

En versiones anteriores de ASP.NET esta característica permitía actualizar parte de la pagina web sin actualizar la pagina completa. Ahora esto lo podemos realizar con AJAX, UpdatePanels, MVC, Web API,m SignalR. 

Browser Capability Detection

Recomendación: Dejar de usarlo, en su lugar utilizar la detección de características dinámicas.

En versiones anteriores de ASP.NEt, las características compatibles para cada navegador se almacenaban en un archivo XML. La detección de soporte de las funciones a través de una consulta estática no es el mejor enfoque. Ahora podemos detectar dinámicamente las funciones compatibles de un navegador utilizando librerías como Modernizr

Seguridad – Request Validation

Recomendación: Validar las entradas de usuario, y codificar la salida hacia los clientes.

El Request Validation es una característica de ASP.NET que inspecciona cada request  ya que detiene este request si encuentra una amenaza. Pero no descansar toda la seguridad de los datos que van hacia el servidor con esta característica. Se debe validar todas las entradas, y en casos más riesgosos en terminos de seguridad, utilizar expresiones regulares, ocupar librerías anti-xss, etc.

Formularios sin cookies de autenticación y sesiones

Recomendación: Requerir cookies.

El paso de información de autenticación en la cadena de consulta no es para nada seguro, por lo tanto , se requieren coockes cuando la aplicación requiera autenticación. Si nuestra cokkie almacna informaci{on sensible, hay que considerar requerir SSL para la cookie.

El siguiente ejemplo muestra como especicificar en un archivo Web.config que la autenticación de formularios reuqiere una cookie a traves de SSL

<authentication mode="Forms">
   <Formas loginUrl = "member_login.aspx"
     sin cookies = "UseCookies"
     requireSSL = "true"
     path = "/ MyApplication" />
 </ Authentication>

EnableViewStateMac

Recomendación: Nunca , pero re-nunca setearlo en False

Por defecto, EnableViewStateMac se establece en true. Incluso si nuestra aplicación no ocupa viewstate, nunca establezcamos este parámetro en false, ya que hará que nuestra app sea vulnerable a cross-site scripting. Si ya la has seteado en false, corre a cambiarlo Sonrisa

Medium Trust

Recomendación: No depender de la confianza media (o cualquier otro nivel de confianza) como límite de seguridad.

La confianza parcial no protege adecuadamente la solicitud y no debe ocuparse, debemos ocupar Full Trust, y aislar las aplicaciones no confiables en app pools distintos. También ejecutar cada app pool bajo una identidad única, para más información de esto podemos visitar ASP.NET Partial Trust does not guarantee application isolation.

<appSettings>

Recomendación: No desactivar la configuración de asegurar en elemento <appSetings>.

El elmento appSetting contiene muchos valores que son necesarios para las actualizaciones de seguridad, no hay que cambiar estos valores. Si tenemos que desactivar estos valores al implementar una actualización, debemos volver a dejarlos como estaban inmediatamente.Revisa más información acá ASP.NET appSettings Element.

UrlPathEncode

Recomendación: utilizar UrlEncode

El método UrlPathEncode se incluyó en el Net framework para resolver un prob lema muy especifico de compatibilidad con ciertos navegadores. Este método no codificia adecuadamente la URL y no protege el request de XSS, así que no lo ocupemos, en su lugar utilicemos UrlEncode.

Ejemplo:

string destinationURL = "http://www.contoso.com/default.aspx?user=test";
NextPage.NavigateUrl = "~/Finish?url=" + Server.UrlEncode(destinationURL);
 
PreSendRequestHeaders y PreSendRequestContext

Recomendación: No utilizar estos eventos con módulos gestionados.

Podemos utilizar los eventos PreSendRequestHeaders y PreSendRequestContext con módulos de IIS nativas, pero no los usemos con módulos gestionados que implementan IHttpModule. La configuración de estas propiedades puede causar problemas con las peticiones asíncronas.

Páginas con eventos asíncronos en WebForms

Recomendación: en los webforms, evitar escribir métodos void asíncronos para los eventos del ciclo de vida de la pagina, y en su lugar utilizar Page.RegisterAsyncTask.

El problema es que cuando no tenemos retorno para un método async no se puede determinar cuando el código asíncrono ha terminado.

Si estamos utilizando tareas asíncronas, setear el framework a 4.5 en el archivo Web.config. NET 4.5 introdujo un nuevo contexto de sincronización, este valor esta seteado por default en los nuevos proyectos, pero si estamos en un proyecto existente, obviamente no.

 <system.web>
     <httpRuntime TargetFramework="4.5" />
 </system.web>
Response.Redirect y Response.End

Recomendación: Tener en cuenta las diferencia en como es manejado el Thread una vez llamado el Responde.redirect(string).

Este método llamada al método Response.End, en un proceso sincrónico, el llamado a Resquest.Redirect hace que el subproceso actual se aborte de inmediato. Sin embargo, en un proceso síncrono el llamada a redirect no aborta el subproceso actual, por lo que la ejecución de código continua. En un proceso asíncrono, deberá devolver la tarea desde el método para detener la ejecución del código. En un proyecto MCV, no hay que llamar a un Response.Redirect, para eso tenemos RedirectResult.

EnableViewState y ViewStateMode

Recomendación: utilizar ViewStateMode en lugar de EnableViewState, que permite un control más detallado sobre el control del ViewState.

Cuando se establece EnableViewState en false en la directiva Page, el viewState queda deshabilitado para todas los controles dentro de la pagina y no se pueden activar individualmente. Si queremos habilitar el ViewState solo para ciertos controles , podemos configurar el viewStateMode para el control en el que necesitemos esta característica.

A nivel de página:
<% @ Page ViewStateMode = “Disabled”.  .  .  %>

y en el control específico:
<asp:GridView ViewStateMode=”Enabled” runat=”server”>

con esto podemos reducir considerablemente el tamaño del viewstate. Sonrisa

Espero que te sirva!!

Saludos!!!
@chalalo