Answers:
我使用JQuery对虚拟HTTP处理程序执行简单的AJAX调用,该处理程序除了使我的Session保持活动之外什么都不做:
function setHeartbeat() {
setTimeout("heartbeat()", 5*60*1000); // 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>
添加从balexandre于2012年8月14日
我非常喜欢这个示例,因此我想通过HTML / CSS和Beat部分进行改进
改变这个
//$("#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">♥</div>
/* HEARBEAT */
.heartbeat {
position: absolute;
display: none;
margin: 5px;
color: red;
right: 0;
top: 0;
}
这是仅一个跳动部分的实时示例:http : //jsbin.com/ibagob/1/
DateTime.Now
只是为了使该会话最近一次通过心跳更新的时间很明显。
如果您使用的是ASP.NET MVC,则不需要其他HTTP处理程序和对web.config文件的某些修改。您所需要的–仅在Home / Common控制器中添加一些简单的操作即可:
[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()", 5*60*1000);
}
function KeepSessionAlive() {
if (keepSessionAlive && keepSessionAliveUrl != null) {
$.ajax({
type: "POST",
url: keepSessionAliveUrl,
success: function () { keepSessionAlive = false; }
});
}
CheckToKeepSessionAlive();
}
,并通过调用JavaScript函数来初始化此功能:
SetupSessionUpdater('/Home/KeepSessionAlive');
请注意!我仅对授权用户实施了此功能(在大多数情况下,没有理由为访客保持会话状态),并且决定保持会话状态为活动状态不仅取决于–是否打开了浏览器,而且授权用户必须执行某些操作在网站上(移动鼠标或键入一些键)。
@Url.Action("KeepSessionAlive","Home")
在初始化函数中使用,这样就不必对URL进行硬编码,也不必将第一个块扔到IIFE内并只需导出,SetupSessionUpdater
因为这是唯一需要在外部调用的东西-例如这:SessionUpdater.js
setInterval(KeepSessionAlive, 300000)
每当您向服务器发出请求时,会话超时都会重置。因此,您可以仅对服务器上的空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-无需在会话中存储变量的开销。仅向服务器执行请求就足够了。
您是否真的需要保留会话(其中是否有数据?)还是通过在请求进入时重新实例化会话来伪造它?如果是第一种,请使用上面的方法。如果是第二种,请尝试使用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);
...
}
并且您将票证生命周期设置为比会话生命周期更长。如果您不进行身份验证,或使用其他身份验证方法,则有类似的技巧。Microsoft TFS Web界面和SharePoint似乎使用了这些-所带来的好处是,如果您单击陈旧页面上的链接,则会在弹出窗口中看到身份验证提示,但是如果您仅使用命令,它就会起作用。
您可以只在您的Java脚本文件中编写此代码。
$(document).ready(function () {
var delay = (20-1)*60*1000;
window.setInterval(function () {
var url = 'put the url of some Dummy page';
$.get(url);
}, delay);
});
该(20-1)*60*1000
是刷新时间,这将刷新会话超时。刷新超时的计算公式为:iis = 20分钟,即20×60000 = 1200000毫秒-60000毫秒(会话到期前一分钟)的默认超时时间是1140000。
如果客户端PC进入睡眠模式,则这是一种可以保留的替代解决方案。
如果您有大量的登录用户,请谨慎使用,因为这可能会占用大量服务器内存。
登录后(我在登录控件的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)
我花了几天时间试图弄清楚如何通过弹出对话框延长WebForms中的用户会话,该对话框为用户提供了续订会话或使其过期的选项。您需要知道的第一件事是,您不需要在其他一些答案中使用任何花哨的“ 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>
关于veggerby的解决方案,如果您尝试在VB应用程序上实现它,请小心尝试通过翻译器运行提供的代码。以下将起作用:
Imports System.Web
Imports System.Web.Services
Imports System.Web.SessionState
Public Class SessionHeartbeatHttpHandler
Implements IHttpHandler
Implements IRequiresSessionState
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Session("Heartbeat") = DateTime.Now
End Sub
End Class
另外,与其像heartbeat()那样调用,不如:
setTimeout("heartbeat()", 300000);
而是这样称呼它:
setInterval(function () { heartbeat(); }, 300000);
第一,setTimeout仅触发一次,而setInterval将重复触发。第二,像字符串一样调用heartbeat()对我不起作用,而像实际函数那样调用它。
我绝对可以100%确认此解决方案将克服GoDaddy的荒谬决定,即在Plesk中强制执行5分钟的应用程序会话!
这里是具有句柄优化的Maryan解决方案的JQuery插件版本。仅适用于JQuery 1.7+!
(function ($) {
$.fn.heartbeat = function (options) {
var settings = $.extend({
// These are the defaults.
events: 'mousemove keydown'
, url: '/Home/KeepSessionAlive'
, every: 5*60*1000
}, 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:6*60*1000}); // different timeout
[晚会上...]
另一种没有Ajax调用或WebService处理程序开销的方法是在给定的时间后(即,在会话状态超时之前,通常是20分钟)加载特殊的ASPX页面:
// Client-side JavaScript
function pingServer() {
// Force the loading of a keep-alive ASPX page
var img = new Image(1, 1);
img.src = '/KeepAlive.aspx';
}
该KeepAlive.aspx
页面只是一个空页面,除了触摸/刷新Session
状态外什么也不做:
// KeepAlive.aspx.cs
public partial class KeepSessionAlive: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Refresh the current user session
Session["refreshTime"] = DateTime.UtcNow;
}
}
这是通过创建img
(图像)元素并强制浏览器从KeepAlive.aspx
页面加载其内容来实现的。加载该页面会导致服务器触摸(更新)Session
对象,从而延长会话的过期滑动时间窗口(通常再延长20分钟)。实际的网页内容被浏览器丢弃。
一种替代的方法,也许是一种更清洁的方法,是创建一个新iframe
元素并将KeepAlive.aspx
页面加载到其中。该iframe
元素是隐藏的,比如通过使一个隐藏的子元素div
在页面上元素的地方。
通过拦截整个页面正文的鼠标和键盘操作,可以检测页面本身上的活动:
// Called when activity is detected
function activityDetected(evt) {
...
}
// Watch for mouse or keyboard activity
function watchForActivity() {
var opts = { passive: true };
document.body.addEventListener('mousemove', activityDetected, opts);
document.body.addEventListener('keydown', activityDetected, opts);
}
我不能相信这个主意。请参阅:https : //www.codeproject.com/Articles/227382/Alert-Session-Time-out-in-ASP-Net。