2009-09-16 136 views
97

只要用户打开浏览器窗口,哪种方法可以让ASP.NET会话保持活动状态,这是最简单和最不危险的方式?它是否定时AJAX调用?我想阻止以下情况:有时用户长时间保持窗口打开,然后输入内容,并且由于服务器端会话过期而不再提交任何内容。我不想在服务器上增加超过10分钟的超时值,因为我想关闭会话(通过关闭浏览器窗口)以快速超时。保持ASP.NET会话打开/活动

建议,代码示例?

+0

您可以检查此链接以获得答案以及http://www.dotnetcurry.com/ShowArticle.aspx?ID=453 – 2016-04-22 13:53:33

回答

156

我使用jQuery执行一个简单的AJAX调用,什么也不做,但保持我的会话有效的虚拟HTTP处理程序:

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" 
    ); 
} 

会话处理程序可以简单到:

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

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

的关键是添加IRequiresSessionState,否则Session将不可用(= null)。如果某些数据应该返回给调用JavaScript,那么处理程序当然也可以返回JSON序列化对象。

提供通过web.config中:

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

8月14日添加balexandre,2012

我非常喜欢的这个例子,我想与改善HTML/CSS和拍子部分

更改此信息

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

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

,并添加

// 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和CSS

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

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

这里是一个活生生的例子只击打部分:http://jsbin.com/ibagob/1/

+21

+1为酷的名字 – Martin 2009-09-16 16:26:36

+2

+1和+ acc为代码的一个很好的解决方案。 – Alex 2009-09-16 20:13:41

+0

@veggerby“添加到一个虚拟的HTTP处理程序,该程序除了保持我的会话不活动外,什么也不做。 您可以发布HTTP Handler的示例代码来保持会话活着吗? – Gopinath 2009-11-03 13:51:13

2

您是否真的需要保持会话(您有数据吗?)还是足以通过在请求进入时重新实例化会话来伪造该会话?如果第一个,使用上面的方法。如果第二个,尝试使用Session_End事件处理程序。

如果您有窗体身份验证,然后你在Global.asax.cs中像

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); 
    ... 
    } 

而且你比会话有效期更长的时间订的机票寿命。如果您没有进行身份验证,或者使用不同的身份验证方法,那么也有类似的技巧。微软的TFS网页界面和SharePoint似乎都使用了这些 - 放弃的是,如果您点击旧页面上的链接,您将在弹出窗口中获得身份验证提示,但如果您只是使用命令,则可以使用。

50

如果您使用ASP。NET MVC - 你不需要额外的HTTP处理程序和web.config文件的一些修改。所有你需要的 - 只是添加一些简单的动作在首页/通用控制器:

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

,写类似这样的一段JavaScript代码(我把它放在网站的JavaScript文件之一):

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(); 
} 

,并通过调用JavaScript函数初始化这个功能:

SetupSessionUpdater('/Home/KeepSessionAlive'); 

请注意!我只为授权用户实现了此功能(在大多数情况下没有任何理由保留来宾的会话状态),并且决定保持会话状态为活动状态不仅仅基于 - 浏览器是否打开,但授权用户必须执行一些操作网站上的活动(移动鼠标或键入某个键)。

+1

对于MVC,我认为这是更好的答案。不需要使用.ashx文件,为什么你会这样? – arame3333 2016-04-25 08:27:17

+0

在** mvc **中检查HTTP处理程序**检查[this](http://www.dotnetcurry.com/ShowArticle.aspx?ID=453),希望可以帮助某人。 – stom 2016-06-12 06:39:01

+1

Maryan,你可能还想在初始化函数中使用'@ Url.Action(“KeepSessionAlive”,“Home”)'''''''''''''''''因此你不必硬编码这个URL,也可以把第一个块放入一个IIFE中,导出'SetupSessionUpdater'因为这是唯一需要在外部调用的东西 - 如下所示:[SessionUpdater.js](https://gist.github.com/KyleMit/aa4f576fa32bf36fbedab5540c18211d#file-sessionupdater-js) – KyleMit 2016-08-29 20:48:25

6

只要向服务器发出请求,会话超时就会重置。所以你可以对服务器上的一个空的HTTP处理器进行ajax调用,但要确保处理器的缓存被禁用,否则浏览器将缓存你的处理器并且不会发出新的请求。

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 - 没有必要在会话存储变量的开销。只需向服务器执行一个请求就足够了。

0

这是另一种解决方案,如果客户端电脑进入睡眠模式,应该可以继续使用。

如果您有大量登录用户,请谨慎使用,因为这可能会消耗大量服务器内存。

登录后(我这样做的登录控制的loggedIn事件)

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

为什么这下来投票?有没有提到它的某种问题?如果是这种情况,请分享,以便将来的读者知道它! – Peter 2016-07-20 08:27:19

1

,你可以只写在你的代码的Java脚本文件完蛋了。

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

1140000是刷新时间,它会刷新会话超时。刷新超时计算为缺省时间超出iis = 20分钟,意味着20×60000 = 1200000毫秒 - 60000毫秒(会话过期前一分钟)为1140000.

0

我花了几天的时间试图弄清楚如何延长WebForms中的用户会话通过弹出对话框提供给用户更新会话或允许其过期的选项。你需要知道的#1事情是,你不需要任何这种奇特的'HttpContext'的东西在其他答案。所有你需要的是jQuery的$ .post();方法。例如,在调试时我用:

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

和运行的网站,你会使用类似:

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

就这么简单。此外,如果你想提示用户选择更新他们会做一些类似下面的内容:

<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> 

不要忘记对话框添加到您的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

这里有处理优化的Maryan解决方案的JQuery插件版本。只有使用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) 

以及如何进行导入在* .cshtml

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