2009-09-16 30 views
97

¿Cuál es la forma más fácil y menos obsesiva de mantener viva una sesión ASP.NET mientras el usuario tenga abierta la ventana del navegador? ¿Se trata de llamadas AJAX temporizadas? Quiero evitar lo siguiente: a veces los usuarios mantienen su ventana abierta durante mucho tiempo, luego ingresan cosas, y al enviar nada, nada funciona porque la sesión del lado del servidor expiró. No deseo aumentar el valor de tiempo de espera durante más de 10 minutos en el servidor, ya que quiero que las sesiones cerradas (al cerrar la ventana del navegador) excedan el tiempo de espera.Mantener ASP.NET Session Open/Alive

Sugerencias, muestras de código?

+0

Puede comprobar este enlace para obtener contestar así http://www.dotnetcurry.com/ShowArticle.aspx?ID=453 –

Respuesta

156

que usar jQuery para realizar una simple llamada AJAX a un controlador HTTP ficticia que no hace más que mantener mi sesión activa:

function setHeartbeat() { 
    setTimeout("heartbeat()", 300000); // every 5 min 
} 

function heartbeat() { 
    $.get(
     "/SessionHeartbeat.ashx", 
     null, 
     function(data) { 
      //$("#heartbeat").show().fadeOut(1000); // just a little "red flash" in the corner :) 
      setHeartbeat(); 
     }, 
     "json" 
    ); 
} 

gestor de sesiones puede ser tan simple como:

public class SessionHeartbeatHttpHandler : IHttpHandler, IRequiresSessionState 
{ 
    public bool IsReusable { get { return false; } } 

    public void ProcessRequest(HttpContext context) 
    { 
     context.Session["Heartbeat"] = DateTime.Now; 
    } 
} 

El la clave es agregar IRequiresSessionState; de ​​lo contrario, Session no estará disponible (= null). El controlador también puede devolver un objeto serializado JSON si algunos datos se deben devolver al JavaScript que realiza la llamada.

disponibles a través de web.config:

<httpHandlers> 
    <add verb="GET,HEAD" path="SessionHeartbeat.ashx" validate="false" type="SessionHeartbeatHttpHandler"/> 
</httpHandlers> 

añadió de balexandre el 14 de agosto, 2012

me gustó tanto de este ejemplo, que quiero mejorar con el HTML/CSS y la parte de compás

cambiar esto

//$("#heartbeat").show().fadeOut(1000); // just a little "red flash" in the corner :) 

en

beatHeart(2); // just a little "red flash" in the corner :) 

y añadir

// beat the heart 
// 'times' (int): nr of times to beat 
function beatHeart(times) { 
    var interval = setInterval(function() { 
     $(".heartbeat").fadeIn(500, function() { 
      $(".heartbeat").fadeOut(500); 
     }); 
    }, 1000); // beat every second 

    // after n times, let's clear the interval (adding 100ms of safe gap) 
    setTimeout(function() { clearInterval(interval); }, (1000 * times) + 100); 
} 

HTML y CSS

<div class="heartbeat">&hearts;</div> 

/* HEARBEAT */ 
.heartbeat { 
    position: absolute; 
    display: none; 
    margin: 5px; 
    color: red; 
    right: 0; 
    top: 0; 
} 

aquí es un ejemplo vivo por sólo la parte golpeo: http://jsbin.com/ibagob/1/

+21

+1 para el nombre genial – Martin

+2

+1 y + acc para una buena solución con código. – Alex

+0

@veggerby "a un manejador HTTP ficticio que no hace más que mantener viva mi sesión". ¿Puede por favor publicar código de muestra del controlador HTTP para mantener viva la sesión? – Gopinath

2

¿Realmente necesita mantener la sesión (¿tiene datos?) O ¿es suficiente para simular esto al volver a iniciar la sesión cuando se recibe una solicitud? Si es el primero, usa el método de arriba. Si es el segundo, intente con algo como usar el controlador de eventos Session_End.

Si tiene autenticación de formularios, a continuación, obtener algo en el Global.asax.cs como

FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(formsCookie.Value); 
if (ticket.Expired) 
{ 
    Request.Cookies.Remove(FormsAuthentication.FormsCookieName); 
    FormsAuthentication.SignOut(); 
    ...    
    } 
else 
{ ... 
    // renew ticket if old 
    ticket = FormsAuthentication.RenewTicketIfOld(ticket); 
    ... 
    } 

y se establece el tiempo de vida de entradas mucho más largo que la duración de la sesión. Si no está autenticando, o usa un método de autenticación diferente, hay trucos similares. La interfaz web Microsoft TFS y SharePoint parecen usar estos: el regalo es que si haces clic en un enlace en una página obsoleta, obtienes indicaciones de autenticación en la ventana emergente, pero si solo usas un comando, funciona.

50

Si está utilizando ASP.NET MVC: no necesita un controlador HTTP adicional y algunas modificaciones del archivo web.config. Todo lo que necesita - sólo para añadir un poco de acción simple en un hogar/controlador común:

[HttpPost] 
public JsonResult KeepSessionAlive() { 
    return new JsonResult {Data = "Success"}; 
} 

, escribir una pieza de código JavaScript como éste (lo he puesto en uno de los archivos JavaScript de sitio):

var keepSessionAlive = false; 
var keepSessionAliveUrl = null; 

function SetupSessionUpdater(actionUrl) { 
    keepSessionAliveUrl = actionUrl; 
    var container = $("#body"); 
    container.mousemove(function() { keepSessionAlive = true; }); 
    container.keydown(function() { keepSessionAlive = true; }); 
    CheckToKeepSessionAlive(); 
} 

function CheckToKeepSessionAlive() { 
    setTimeout("KeepSessionAlive()", 300000); 
} 

function KeepSessionAlive() { 
    if (keepSessionAlive && keepSessionAliveUrl != null) { 
     $.ajax({ 
      type: "POST", 
      url: keepSessionAliveUrl, 
      success: function() { keepSessionAlive = false; } 
     }); 
    } 
    CheckToKeepSessionAlive(); 
} 

, e inicializar esta funcionalidad llamando a una función de JavaScript:

SetupSessionUpdater('/Home/KeepSessionAlive'); 

¡Atención! Implementé esta funcionalidad solo para usuarios autorizados (no hay motivo para mantener el estado de la sesión para invitados en la mayoría de los casos) y la decisión de mantener el estado de sesión activo no solo se basa en - está abierto o no el navegador, pero el usuario autorizado debe hacer actividad en el sitio (mueva un mouse o escriba alguna clave).

+1

Para MVC, creo que esta es la mejor respuesta. No es necesario usar el archivo .ashx, ¿por qué lo harías? – arame3333

+0

Con ** HTTP Handler en asp mvc ** compruebe [this] (http://www.dotnetcurry.com/ShowArticle.aspx?ID=453), la esperanza ayuda a alguien. – stom

+1

Maryan, es posible que también desee utilizar '@ Url.Action (" KeepSessionAlive "," Home ")' en la función de inicialización para que no tenga que codificar el URL y también arroje el primer bloque dentro de un IIFE y solo Exporte el 'SetupSessionUpdater' ya que es lo único que debe invocarse externamente, algo como esto: [SessionUpdater.js] (https://gist.github.com/KyleMit/aa4f576fa32bf36fbedab5540c18211d#file-sessionupdater-js) – KyleMit

6

Cada vez que realiza una solicitud al servidor, se restablece el tiempo de espera de la sesión. Por lo tanto, puede hacer una llamada ajax a un manejador HTTP vacío en el servidor, pero asegúrese de que la memoria caché del manejador esté desactivada, de lo contrario, el navegador guardará en caché su controlador y no realizará una nueva solicitud.

KeepSessionAlive.ashx.cs

public class KeepSessionAlive : IHttpHandler, IRequiresSessionState 
    { 

     public void ProcessRequest(HttpContext context) 
     { 
      context.Response.Cache.SetCacheability(HttpCacheability.NoCache); 
      context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1)); 
      context.Response.Cache.SetNoStore(); 
      context.Response.Cache.SetNoServerCaching(); 
     } 
    } 

.JS:

window.onload = function() { 
     setInterval("KeepSessionAlive()", 60000) 
} 

function KeepSessionAlive() { 
url = "/KeepSessionAlive.ashx?"; 
     var xmlHttp = new XMLHttpRequest(); 
     xmlHttp.open("GET", url, true); 
     xmlHttp.send(); 
     } 

@veggerby - no hay necesidad de que la sobrecarga de almacenar variables en la sesión. Solo es necesario realizar una solicitud al servidor.

0

Aquí hay una solución alternativa que debería sobrevivir si la PC del cliente entra en modo de suspensión.

Si tiene una gran cantidad de usuarios conectados, utilice esto con cuidado ya que podría consumir mucha memoria del servidor.

Después de hacer login (hago esto en el caso loggedin del control de acceso)

Dim loggedOutAfterInactivity As Integer = 999 'Minutes 

'Keep the session alive as long as the authentication cookie. 
Session.Timeout = loggedOutAfterInactivity 

'Get the authenticationTicket, decrypt and change timeout and create a new one. 
Dim formsAuthenticationTicketCookie As HttpCookie = _ 
     Response.Cookies(FormsAuthentication.FormsCookieName) 

Dim ticket As FormsAuthenticationTicket = _ 
     FormsAuthentication.Decrypt(formsAuthenticationTicketCookie.Value) 
Dim newTicket As New FormsAuthenticationTicket(
     ticket.Version, ticket.Name, ticket.IssueDate, 
     ticket.IssueDate.AddMinutes(loggedOutAfterInactivity), 
     ticket.IsPersistent, ticket.UserData) 
formsAuthenticationTicketCookie.Value = FormsAuthentication.Encrypt(newTicket) 
+0

¿Por qué fue? esto abajo votado? ¿Hay algún tipo de problema que no he mencionado? si ese es el caso, comparta para que los futuros lectores lo sepan. – Peter

1

sólo puede escribir este código en el archivo de java script que eso es todo.

$(document).ready(function() { 
     window.setInterval(function() { 
      var url = 'put the url of some Dummy page'; 
      $.get(url);     
     },1140000); 
}); 

El 1140000 es el tiempo de actualización, se actualizará el tiempo de espera de la sesión. El tiempo de espera de actualización se calcula como el tiempo predeterminado de iis = 20 minutos, significa 20 × 60000 = 1200000 milisegundos - 60000 milisegundos (Un minuto antes de que la sesión caduque) es 1140000.

0

Pasé unos días tratando de descubrir cómo prolongar una sesión de usuarios en WebForms a través de un diálogo emergente que le da al usuario la opción de renovar la sesión o permitir que caduque. Lo # 1 que debes saber es que no necesitas que nada de este elegante material de "HttpContext" continúe en algunas de las otras respuestas. Todo lo que necesitas es jQuery's $ .post(); método. Por ejemplo, durante la depuración utilicé:

$.post("http://localhost:5562/Members/Location/Default.aspx"); 

y en su sitio vivo que usaría algo como:

$.post("http://mysite/Members/Location/Default.aspx"); 

Es tan fácil como eso.Por otra parte, si desea pedir al usuario con la opción de renovar su sesión de hacer algo similar a lo siguiente:

<script type="text/javascript"> 
    $(function() { 
     var t = 9; 
     var prolongBool = false; 
     var originURL = document.location.origin; 
     var expireTime = <%= FormsAuthentication.Timeout.TotalMinutes %>; 

     // Dialog Counter 
     var dialogCounter = function() { 
      setTimeout(function() { 
       $('#tickVar').text(t); 
        t--; 
        if(t <= 0 && prolongBool == false) { 
         var originURL = document.location.origin; 
         window.location.replace(originURL + "/timeout.aspx"); 
         return; 
        } 
        else if(t <= 0) { 
         return; 
        } 
        dialogCounter(); 
      }, 1000); 
     } 

     var refreshDialogTimer = function() { 
      setTimeout(function() { 
       $('#timeoutDialog').dialog('open'); 
      }, (expireTime * 1000 * 60 - (10 * 1000))); 
     }; 

     refreshDialogTimer(); 

     $('#timeoutDialog').dialog({ 
      title: "Session Expiring!", 
      autoOpen: false, 
      height: 170, 
      width: 350, 
      modal: true, 
      buttons: { 
       'Yes': function() { 
        prolongBool = true; 
        $.post("http://localhost:5562/Members/Location/Default.aspx"); 
        refreshDialogTimer(); 
        $(this).dialog("close"); 
       }, 
       Cancel: function() { 
        var originURL = document.location.origin; 
        window.location.replace(originURL + "/timeout.aspx"); 
       } 
      }, 
      open: function() { 
       prolongBool = false; 
       $('#tickVar').text(10); 
       t = 9; 
       dialogCounter(); 
      } 
     }); // end timeoutDialog 
    }); //End page load 
</script> 

No se olvide de añadir el diálogo a su html:

 <div id="timeoutDialog" class='modal'> 
      <form> 
       <fieldset> 
        <label for="timeoutDialog">Your session will expire in</label> 
        <label for="timeoutDialog" id="tickVar">10</label> 
        <label for="timeoutDialog">seconds, would you like to renew your session?</label> 
       </fieldset> 
      </form> 
     </div> 
0

Aquí, versión del complemento JQuery de la solución Maryan con optimización del manipulador. ¡Solo con JQuery 1.7+!

(function ($) { 
    $.fn.heartbeat = function (options) { 
     var settings = $.extend({ 
      // These are the defaults. 
      events: 'mousemove keydown' 
      , url: '/Home/KeepSessionAlive' 
      , every: 300000 
     }, options); 

     var keepSessionAlive = false 
     , $container = $(this) 
     , handler = function() { 
      keepSessionAlive = true; 
      $container.off(settings.events, handler) 
     }, reset = function() { 
      keepSessionAlive = false; 
      $container.on(settings.events, handler); 
      setTimeout(sessionAlive, settings.every); 
     }, sessionAlive = function() { 
      keepSessionAlive && $.ajax({ 
       type: "POST" 
       , url: settings.url 
       ,success: reset 
       }); 
     }; 
     reset(); 

     return this; 
    } 
})(jQuery) 

y cómo lo hace de importación en su * .cshtml

$('body').heartbeat(); // Simple 
$('body').heartbeat({url:'@Url.Action("Home", "heartbeat")'}); // different url 
$('body').heartbeat({every:400000}); // different timeout