保持ASP.NET会话开放/活跃

时间:2009-09-16 08:40:43

标签: c# asp.net session

只要用户打开浏览器窗口,哪种最简单,最不显眼的方式可以使ASP.NET会话保持活动状态?是时候调用AJAX吗?我想阻止以下情况:有时候用户长时间打开窗口,然后输入内容,并且提交时不再有效,因为服务器端会话已过期。我不希望在服务器上将超时值增加超过10分钟,因为我希望关闭会话(通过关闭浏览器窗口)快速超时。

建议,代码示例?

10 个答案:

答案 0 :(得分:166)

我使用JQuery对虚拟HTTP处理程序执行一个简单的AJAX调用,该处理程序除了保持会话活动外什么都不做:

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>

于2012年8月14日从balexandre添加

我非常喜欢这个例子,我想用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/

答案 1 :(得分:61)

如果您使用的是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()", 300000);
}

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

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

SetupSessionUpdater('/Home/KeepSessionAlive');

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

答案 2 :(得分:7)

每当您向服务器发出请求时,会话超时都会重置。因此,您只需对服务器上的空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 - 不需要在会话中存储变量的开销。只需向服务器执行请求就足够了。

答案 3 :(得分: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);
    ...
     }

您设置的票证有效期比会话有效期长得多。如果您没有进行身份验证或使用其他身份验证方法,则会有类似的技巧。 Microsoft TFS Web界面和SharePoint似乎使用这些 - 赠送的是,如果您单击过时页面上的链接,您将在弹出窗口中获得身份验证提示,但如果您只是使用命令,则它可以正常工作。

答案 4 :(得分:2)

你可以在这个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.

答案 5 :(得分: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)

答案 6 :(得分:0)

我花了几天时间试图找出如何通过弹出对话框延长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>

答案 7 :(得分:0)

这里是JQuery插件版本的Maryan解决方案,带有句柄优化功能。仅限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

答案 8 :(得分:0)

关于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分钟的apppool会话!

答案 9 :(得分:0)

[该晚了……]

另一种没有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