web-dev-qa-db-ja.com

ASP.NETセッションを開いたままにしておく

ユーザーがブラウザウィンドウを開いている限り、ASP.NETセッションを存続させる最も簡単で目立たない方法はどれですか? AJAX呼び出しのタイミングですか?私は次のことを防ぎたい:時々ユーザーはウィンドウを長時間開いたままにしてから何かを入力し、サーバー側のセッションが期限切れになったので送信時に何も機能しなくなる。閉じられたセッション(ブラウザーウィンドウを閉じること)が高速にタイムアウトするように、サーバーで10分以上タイムアウト値を増やしたくありません。

提案、コードサンプル?

110
Alex

私は、JQueryを使用して、単純なAJAXダミーのHTTPハンドラーへの呼び出しを実行します。

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を追加することです。そうしないと、セッションが使用できなくなります(= null)。もちろん、呼び出し側のJavaScriptにデータを返す必要がある場合、ハンドラーはJSONシリアル化オブジェクトを返すこともできます。

Web.configを介して利用可能になりました:

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

addedfrom balexandre 2012年8月14日

この例がとても気に入ったので、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/

167
veggerby

ASP.NET MVCを使用している場合、追加のHTTPハンドラーとweb.configファイルのいくつかの変更は必要ありません。必要なもの-単純なアクションをHome/Commonコントローラーに追加するだけです:

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

、次のようなJavaScriptコードを記述します(サイトのJavaScriptファイルの1つに入れました)。

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');

注意してください!この機能を許可されたユーザーのみに実装しました(ほとんどの場合、ゲストのセッション状態を保持する理由はありません)。許可されていないユーザーでも、サイト上で何らかの操作を行う必要があります(マウスを動かすか、キーを入力します)。

64
Maryan

サーバーにリクエストを行うと、セッションタイムアウトがリセットされます。したがって、サーバー上の空の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-セッションに変数を保存するオーバーヘッドは必要ありません。サーバーにリクエストを実行するだけで十分です。

8
BornToCode

このコードを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ミリ秒(セッションが期限切れになる1分前)が1140000であることを意味します。

2
ANKIT KISHOR

本当にセッションを維持する必要がありますか(セッションにデータがありますか?)、または要求が来たときにセッションを再インスタンス化することでこれを偽造するのに十分ですか?最初の場合、上記の方法を使用します。 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はこれらを使用しているようです-古いページのリンクをクリックすると、ポップアップウィンドウに認証プロンプトが表示されますが、コマンドを使用するだけで機能します。

2
Henry Troup

クライアント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)
0
Peter

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

1つ目は、setIntervalが繰り返し発生するのに対して、setTimeoutは1回だけ発生します。 2つ目は、文字列のようにheartbeat()を呼び出しても機能しませんでしたが、実際の関数のように呼び出すと機能しませんでした。

そして、このソリューションがPleskで5分間のアプリプールセッションを強制するというGoDaddyのばかげた決定を克服することを、絶対に100%確認できます!

0
ShowJX1990

ポップアップダイアログを使用して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>

Dialogを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
Versatile

ここで、ハンドル最適化を備えた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
0
AlexPalla

[パーティーに遅れて...]

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分)を延長します。実際のWebページのコンテンツは、ブラウザーによって破棄されます。

ページ自体のアクティビティは、ページ本文全体のマウスとキーボードのアクションをインターセプトすることで検出できます。

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

0
David R Tribble