ASP.NETセッションを開いたまま/維持する


115

ユーザーがブラウザーウィンドウを開いている限り、ASP.NETセッションを存続させる最も簡単で最も邪魔にならない方法はどれですか。時限AJAX呼び出しですか?以下を防止したいと思います。ユーザーがウィンドウを長時間開いたままにして、何かを入力すると、サーバー側のセッションが期限切れになったため、送信時に何も動作しなくなります。(ブラウザーウィンドウを閉じることによって)セッションを閉じて高速にタイムアウトさせたいので、サーバーでタイムアウト値を10分を超えて大きくしたくありません。

提案、コードサンプル?


このリンクをチェックして回答を取得することもできます。dotnetcurry.com/ ShowArticle.aspx?ID
Developer

回答:


170

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

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>

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/


@veggerby「セッションを存続させるだけで何もしないダミーのHTTPハンドラーへ」。セッションを存続させるために、HTTPハンドラーのサンプルコードを投稿していただけますか?
Gopinath

いいえ、そこにある唯一の選択肢は(おそらく)セッションタイムアウトを増やすことですが、長期的にはこれはおそらく悪い考えです
veggerby

関連する問題の調査を行っていて、このソリューションに出くわしました。いい物。ただし、1つのクエリとして、ユーザーがブラウザーを開いたままにして、PCが10時間スリープしないと言った場合、セッションはそのような長い間存続します。これは正解?
ジュリアスA

2
うまくいきましたが、キャッシュバーストをコールに追加するまでは失敗しました。このキャッシュバーストパラメータがないと、コントローラは初めて呼び出されます
ジャン

1
@stomこれは、タイムアウトなどではなく、セッション値であること意味します。使用する理由はDateTime.Now、セッションがハートビートを介して最後に更新されたときにそれを明らかにするためです。
veggerby

69

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

ご注意ください!私はこの機能を許可されたユーザーのみに実装しました(ほとんどの場合、ゲストのセッション状態を維持する理由はありません)。セッション状態をアクティブにしておくかどうかの決定は、ブラウザが開いているかどうかだけではありませんが、許可されたユーザーは何らかのアクティビティを行う必要がありますサイト上(マウスを移動するか、キーを入力)。


3
MVCの場合、これがより良い答えだと思います。.ashxファイルを使用する必要はありません。なぜでしょうか。
arame3333

HTTPハンドラASPでMVC確認し、これを、希望は誰かに役立ちます。
shaijut

3
Maryan、@Url.Action("KeepSessionAlive","Home")イニシャライザ関数で使用することもできます。これにより、URLをハードコードする必要がなく、IIFE内の最初のブロックをスローしてエクスポートSetupSessionUpdaterするだけです。 this:SessionUpdater.js
KyleMit

setIntervalが使用されない理由はありますか? setInterval(KeepSessionAlive, 300000)
Matthieu Cormier

8

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


2

本当にセッションを維持する必要がありますか(データが含まれていますか?)、またはリクエストが来たときにセッションを再インスタンス化することでこれを偽造するのに十分ですか?最初の場合は、上記の方法を使用します。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

あなたはちょうどあなたがそれをそれであるあなたの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です。


0

以下は、クライアント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)

なぜこれは反対票が投じられたのですか?私が言及しなかったある種の問題がありますか?その場合は共有してください。そうすれば、将来の読者がそれを認識できるようになります。
Peter

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>

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

1つ目は、setTimeoutが1回だけ起動するのに対し、setIntervalは繰り返し起動することです。2つ目は、文字列のようにheartbeat()を呼び出しても機能しなかったのに対し、実際の関数のように呼び出した場合です。

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


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

[パーティーの後半...]

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ページのコンテンツは、ブラウザーによって破棄されます。

これを行うための代替の、そしておそらくよりクリーンな方法は、新しい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を参照して ください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.