Estado de sesión
ASP.NET proporciona la infraestructura de información del estado de una solicitud a otra (carritos de la compra, desplazamiento de datos, etc.) que necesitan las aplicaciones Web, con una funcionalidad integrada de estado de sesión que permite realizar las siguientes acciones:
Identificar y clasificar automáticamente solicitudes provenientes de un solo cliente explorador en una sesión lógica de aplicación en el servidor.
Almacenar datos del ámbito de una sesión en el servidor para utilizarlos en diversas solicitudes de explorador.
Provocar eventos adecuados de administración del tiempo de vida de la sesión (Session_OnStart, Session_OnEnd, etc.) que se pueden controlar con código de aplicación.
Nota El evento Session_OnEnd admite sólo el modo de estado de sesión en proceso. Este evento no se provoca si se utilizan los modos de servidor de estado o SQL Server.
Liberar automáticamente datos de las sesiones si el explorador no vuelve a visitar una aplicación dentro del período de espera que se haya especificado.
En este tema se proporciona información general acerca del estado de sesión, se describe cómo identificar y realizar un seguimiento de las sesiones ASP.NET activas, se explica la estructura del almacén de estados de sesión y la estructura general, y como conclusión, se ofrece un ejemplo de código de alto nivel.
Información general acerca del estado de sesión
HTTP es un protocolo sin estado, es decir, que no indica automáticamente si una secuencia de solicitudes proviene del mismo cliente ni si una sola instancia de explorador sigue viendo activamente una página o un sitio. En consecuencia, la creación de aplicaciones Web que necesitan mantener información del estado de una solicitud a otra (carros de la compra, desplazamiento de datos, etc.) puede resultar sumamente complicada sin la ayuda adicional de una infraestructura.
ASP.NET proporciona los siguientes elementos de compatibilidad con las sesiones:
- Un servicio de estado de sesión fácil de utilizar, coherente con otras API de .NET Framework y con el que están familiarizados los programadores de ASP.
- Un servicio seguro de estado de sesión que puede sobrevivir a reinicios de los Servicios de Internet Information Server (IIS) y a reinicios de procesos de trabajo sin perder datos de las sesiones.
- Un servicio escalable de estado de sesión que se puede utilizar en un escenario de matriz de servidores Web (múltiples equipos) o en un escenario de matriz de procesos Web (múltiples procesos), y que permite a los administradores asignar más procesadores a una aplicación Web para mejorar su escalabilidad.
- Un servicio de estado de sesión que funciona con exploradores que no son compatibles con cookies HTTP.
- Un rendimiento equivalente al de ASP (o mejor) para escenarios básicos de estado de sesión (mitad lectura y mitad escritura cuando se colocan elementos en carros de la compra, se modifica la última página visitada, se validan los detalles de una tarjeta de crédito, etc.).
El estado de sesión, sin embargo, no se conserva entre los límites de las aplicaciones Web. Si se pasa de una aplicación Web a otra durante una ejecución, la información de sesión no está disponible en la nueva aplicación.
Identificar una sesión
Para identificar y realizar un seguimiento de cada sesión ASP.NET activa se utiliza una cadena SessionID de 120 bits que sólo contiene los caracteres ASCII permitidos en las direcciones URL. Los valores SessionID se generan con un algoritmo que garantiza que son únicos, de manera que no haya conflictos entre sesiones, y que son aleatorios, de manera que ningún usuario malintencionado pueda utilizar un nuevo objeto SessionID para calcular el identificador de una sesión existente.
Las cadenas SessionID se transmiten a través de solicitudes cliente-servidor mediante un cookie HTTP o una dirección URL modificada con la cadena SessionID incrustada, dependiendo de cómo configure la aplicación.
Almacén de estados de sesión
ASP.NET proporciona un modelo de estado de sesión sencillo y fácil de utilizar que se puede emplear para almacenar datos y objetos arbitrarios de varias solicitudes Web. Para ello, utiliza una caché en memoria basada en un diccionario que contiene referencias a objetos que residen en el proceso IIS. Cuando se utiliza el modo de estado de sesión en proceso hay que tener en cuenta las siguientes limitaciones:
- Cuando se utiliza este modo, los datos del estado de sesión se pierden si se reinicia aspnet_wp.exe o el dominio de aplicación. Estos reinicios se producen, generalmente, en las circunstancias siguientes:
- Se establece un atributo en el elemento <processModel> del archivo Web.config de la aplicación, que hace que se inicie un nuevo proceso si se cumple una condición, como memoryLimit.
- Se modifica el archivo Global.asax o el archivo Web.config.
- Se cambia al directorio \Bin de la aplicación Web.
- El software de un antivirus examina y modifica el archivo Global.asax, el archivo Web.config o uno de los archivos del directorio \Bin de la aplicación Web.
- Si habilita el modo de matriz de procesos Web en el elemento <processModel> del archivo Web.config de la aplicación, no utilice el modo de estado de sesión en proceso. En caso contrario, se puede producir una pérdida de datos aleatoria.
En vez de guardar objetos activos, el servidor de estado de .NET se limita a almacenar el estado de sesión en la memoria cuando está en modo fuera de proceso. En este modo, el proceso de trabajo se comunica directamente con el servidor de estado. En el modo SQL, los estados de sesión se almacenan en una base de datos de SQL Server y el proceso de trabajo se comunica directamente con SQL. Después, los procesos de trabajo de ASP.NET pueden aprovechar este sencillo servicio de almacenamiento, para lo que serializan y guardan (mediante los servicios de serialización de .NET) todos los objetos de la colección Session de un cliente al final de cada solicitud Web. Cuando el cliente vuelve a visitar el servidor, el correspondiente proceso de trabajo de ASP.NET recupera estos objetos desde el servidor de estado en forma de secuencias binarias, las deserializa para convertirlas en instancias activas y las coloca en una colección Session nueva expuesta al controlador de solicitudes.
En el modo SQL, también se puede configurar el estado de sesión de forma que funcione en un clúster de conmutación por error. Un clúster de conmutación por error está formado por dos o más servidores Web redundantes e idénticos que almacenan los datos de sesión en la base de datos SQL Server de otro equipo. Para obtener más información acerca de esta configuración, vea Configurar el modo SQL Server.
Al separar limpiamente el almacenamiento de datos de sesión del uso que la aplicación hace de él, ASP.NET admite varios escenarios de gran eficacia que no estaban disponibles con versiones anteriores de ASP:
Recuperación tras errores de la aplicación, ya que la memoria utilizada para el estado de sesión no está incluida en el proceso de trabajo de ASP.NET.
Como el estado se almacena independientemente de cualquier proceso de trabajo individual, no se pierde si el proceso se bloquea debido a una infracción de acceso o si el servicio de administración de IIS exige su reinicio en el caso de un bloqueo irreversible o de una pérdida de memoria.
Partición de una aplicación entre varios procesos de trabajo.
Debido a que el estado se almacena independientemente de los procesos de trabajo, puede crear particiones de una aplicación para múltiples procesos. Dichas particiones pueden mejorar notablemente la disponibilidad y la escalabilidad de una aplicación en equipos de múltiples procesos. Además, debido a que asocia cada proceso de trabajo con un único equipo, ASP.NET puede eliminar la contención de mediante loqueos entre procesadores, uno de los principales cuellos de botella para la escalabilidad en versiones anteriores de ASP.
Partición de una aplicación entre varios equipos de una matriz de servidores Web.
Debido a que el estado se almacena independientemente de los procesos de trabajo, puede crear particiones de una aplicación para múltiples procesos de trabajo que se ejecuten en distintos equipos. El modelo para el estado de comunicación entre un proceso de trabajo y un servicio de estado que se ejecutan en distintos equipos es prácticamente igual que el modelo para procesos y servidores que se ejecutan en el mismo equipo. En cualquiera de los dos casos, sólo puede haber un servidor de estado en cada matriz de servidores Web.
Estructura del estado de sesión
Las aplicaciones basadas en ASP.NET utilizan una organización de ejecución basada en eventos para permitir que varios módulos de clases de .NET Framework participen en el procesamiento de una única solicitud Web.
Módulo SessionState
.NET Framework implementa el estado de sesión mediante la clase SessionStateModule (derivada de IHttpModule), que participa en la ejecución de todas las solicitudes recibidas por una aplicación basada en .NET. El módulo SessionState es responsable de generar u obtener cadenas SessionID únicas, y de almacenar y recuperar los datos del estado desde un proveedor externo de estados.
Colecciones de estados de sesión
La clase SessionState expone dos colecciones de estado: Contents y StaticObjects. La colección Contents expone todos los elementos variables que se han agregado a la colección de estados de sesión directamente mediante código. Por ejemplo:
' Visual Basic code from within a page, a handler, or Global.asax.
Session("Message") = "MyMsg"
Session("AppStartTime") = Now
[C#]
// C# code from within a page, a handler, or Global.asax.
Session["Message"] = "MyMsg";
Session["AppStartTime"] = DateTime.Now;
En el caso de versiones anteriores de ASP, también se puede tener acceso a estos valores mediante una propiedad Contents del objeto de aplicación, como se indica en el ejemplo siguiente.
' Visual Basic code from within a page, a handler, or Global.asax.
Session.Contents("Message") = "MyMsg"
Session.Contents("AppStartTime") = Now
[C#]
// C# code from within a page, a handler, or Global.asax.
Session.Contents["Message"] = "MyMsg";
Session.Contents["AppStartTime"] = DateTime.Now;
La colección StaticObjects expone todos los elementos variables que se han agregado a la colección de estados de sesión mediante etiquetas <object runat="server"> con el ámbito de "Session" en el archivo Global.asax. Por ejemplo:
' Global.asax definition.
<OBJECT RUNAT="SERVER" SCOPE="SESSION" ID="MyInfo" PROGID="Scripting.Dictionary">
</OBJECT>
No se pueden agregar objetos a la colección StaticObjects desde ningún otro sitio de una aplicación ASP.NET. La colección generará una excepción NotSupportedException si los usuarios intentan agregar objetos directamente mediante código.
Nota El compilador de páginas de ASP.NET escribe automáticamente referencias a miembros en todos los objetos almacenados en la colección StaticObjects durante la compilación de las páginas.
Los programadores de páginas pueden tener acceso a objetos Session directamente durante las solicitudes de páginas sin tener que pasar por la colección StaticObjects, tal como se muestra en el siguiente ejemplo:
<html>
</body>
Number of entries: <%= MyInfo.Count %>
<body>
</html>
Configuración e inicio del estado de sesión
En ASP.NET existen los tres modos de estado de sesión siguientes: en proceso, servidor de estado y SQL Server. Independientemente del modo que se seleccione, el proceso de configuración básico es el mismo.
ASP.NET configura el estado de sesión en dos fases. En primer lugar, se inserta el módulo de estado de sesión en la solicitud HTTP. De manera predeterminada, se inserta en la raíz de la jerarquía de configuración en el archivo Machine.config que afecta a todo el equipo.
En el ejemplo siguiente se muestra como incluir una entrada en el archivo Machine.config. Para que el archivo de configuración funcione correctamente, debe proporcionar el nombre completo del ensamblado para la versión apropiada del ensamblado System.Web.SessionState.SessionStateModule. Esta es la versión que, por lo general, se asocia con la versión de .NET Framework utilizada por la aplicación. Para más información sobre cómo obtener el nombre completo de un ensamblado, vea Nombres de ensamblados.
<httpmodules>
...
<!-- You must supply a valid fully qualified assembly name here. -->
<!-- For this example to work correctly, the version number for -->
<!-- the referenced assemby must match the version installed on -->
<!-- your computer by the .NET Framework. -->
<add name="sessionState" type="System.Web.SessionState.SessionStateModule, Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" />
...
</httpmodules>
A continuación, dependiendo del modo de estado de sesión que utilice, establezca los atributos de servicio de estado de sesión adecuados en el elemento de configuración <sessionState>.
Configurar el modo en proceso
En proceso es el modo de estado de sesión predeterminado. Para utilizar el modo en proceso, establezca el atributo mode del elemento <sessionState> en Inproc.
A continuación, se muestra un valor de configuración de ejemplo para el modo en proceso.
<configuration>
<system.web>
<sessionState mode="Inproc"
cookieless="false"
timeout="20"/>
</sessionState>
</system.web>
</configuration>
Configurar el modo de servidor de estado
Para utilizar el servidor de estado, primero debe asegurarse de que el servicio de estado de ASP.NET se está ejecutando en el servidor remoto utilizado para el almacén de sesiones. Este servicio se instala con ASP.NET y Visual Studio .NET en la siguiente ubicación:
raízdelsistema\Microsoft.NET\Framework\númerodeversión\aspnet_state.exe
A continuación, en el archivo de configuración Web.config de la aplicación establezca el atributo mode del elemento <sessionState> en StateServer. Por último, establezca el atributo connectionString en **tcpip=serverName:**portNumber.
A continuación, se muestra una opción de configuración de ejemplo para el modo de servidor de estado.
<configuration>
<system.web>
<sessionState mode="StateServer"
stateConnectionString="tcpip=dataserver:42424"
cookieless="false"
timeout="20"/>
</sessionState>
</system.web>
</configuration>
Configurar el modo SQL Server
Para utilizar SQL Server, primero debe ejecutar InstallSqlState.sql o InstallPersistSqlState.sql en el equipo con SQL Server en el que se va a almacenar el estado de sesión. Las dos secuencias de comandos crean una base de datos denominada ASPState que incluye varios procedimientos almacenados. La diferencia entre las secuencias de comandos radica en los lugares en los que se colocan las tablas ASPStateTempApplications y ASPStateTempSessions. La secuencia de comandos InstallSqlState.sql agrega estas tablas a la base de datos TempDB, que pierde los datos de sesión si se reinicia el equipo. La secuencia de comandos InstallPersistSqlState.sql, por otra parte, agrega estas tablas a la base de datos ASPState, que permite conservar los datos de sesión cuando se reinicia el equipo.
Estos dos archivos de secuencias de comandos se instalan de forma predeterminada en la siguiente ubicación:
raízdelsistema\Microsoft.NET\Framework\númerodeversión
A continuación, en el archivo de configuración Web.config de la aplicación establezca el atributo mode del elemento <sessionState> en SQLServer. Por último, establezca el atributo sqlconnectionString en Integrated Security=SSPI;data source=serverName;.
A continuación, se muestra una opción de configuración de ejemplo para el modo SQL Server.
<configuration>
<system.web>
<sessionState mode="SQLServer"
sqlConnectionString=" Integrated Security=SSPI;data source=dataserver;"
cookieless="false"
timeout="20"/>
</sessionState>
</system.web>
</configuration>
En el modo SQL Server, también se puede configurar el estado de sesión de forma que funcione en un clúster de conmutación por error. Un clúster de conmutación por error está formado por dos o más servidores Web redundantes e idénticos que almacenan los datos de sesión en la base de datos SQL Server de otro equipo. Si se produce un error en un servidor Web, otro servidor del clúster asume el control y atiende las solicitudes sin que se produzca una pérdida de datos de sesión. Para configurar un clúster de conmutación por error, establezca el elemento <machinekey> del archivo Web.config en el mismo valor para todos los servidores Web. A continuación, en el equipo donde se almacenan los datos de sesión, establezca la cadena de conexión SQL de los servidores Web de forma que apunte a la base de datos SQL Server.
Ejemplo de código de alto nivel
En el siguiente ejemplo se muestra cómo obtener acceso a los datos existentes del estado de sesión con un método de sólo lectura para generar de forma dinámica una página que contenga información sobre el usuario y sobre su cartera de acciones.
<%@ Language=VB EnableSessionState=true %>
<html>
<head>
<script runat="server">
Sub Page_Load(ByVal Sender as Object, ByVal E as EventArgs)
' Obtain data table of user's personal stock data.
Dim MyStocks as DataTable
Dim Stock as DataRow
MyStocks = _
CType(Session("PersonalStockData"), DataTable)
' Update HTML output with session values.
Name.InnerText = Session("FirstName").ToString()
SpouseVal.InnerText = Session("SpouseName").ToString()
For Each Stock In MyStocks.Rows
StockList.AddItem(Stock("Symbol") & ": " & Stock("Name"))
Next
End Sub
</script>
</head>
<body>
Hi <span id="Name" runat=server/>, your spouse is: <span id="SpouseVal" runat="server"/>.
Here are the stocks you and your spouse currently own:
<acme:listbox id="StockList" runat="server">
<! — List box is dynamically populated from code. -->
</acme:listbox>
</body>
</html>
[C#]
<%@ Language=C# EnableSessionState=true %>
<html>
<head>
<script runat=server>
void Page_Load(Object Sender, EventArgs E) {
// Obtain data table of user's personal stock data.
DataTable MyStocks =
(DataTable)Session["PersonalStockData"];
// Update HTML output with session values.
Name.InnerText = Session["FirstName"].ToString();
SpouseVal.InnerText = Session["SpouseName"].ToString();
foreach (DataRow Stock in MyStocks.Rows) {
StockList.AddItem(Stock["Symbol"] + ": "
+ Stock["Name"]);
}
}
</script>
</head>
<body>
Hi <span id="Name" runat="server"/>, your spouse is: <span id="SpouseVal" runat="server"/>.
Here are the stocks you and your spouse currently own:
<acme:listbox id="StockList" runat="server">
<! — List box is dynamically populated from code. -->
</acme:listbox>
</body>
</html>