ASP.NET 세션을 개방 / 활성 유지


115

사용자가 브라우저 창을 열어 두는 한 ASP.NET 세션을 유지하는 가장 쉽고 눈에 띄지 않는 방법은 무엇입니까? 정기 AJAX 호출입니까? 다음을 방지하고 싶습니다. 때때로 사용자는 창을 오랫동안 열어 둔 다음 항목을 입력하고 제출할 때 서버 측 세션이 만료 되었기 때문에 더 이상 작동하지 않습니다. 닫힌 세션 (브라우저 창을 닫음)이 빠르게 시간 초과되기를 원하므로 서버에서 10 분 이상 시간 초과 값을 늘리고 싶지 않습니다.

제안, 코드 샘플?


이 링크를 확인하여 답변을 얻을 수 있습니다. dotnetcurry.com/ShowArticle.aspx?ID=453
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를 추가하는 것입니다. 그렇지 않으면 세션을 사용할 수 없습니다 (= null). 물론 일부 데이터를 호출하는 JavaScript로 반환해야하는 경우 핸들러는 JSON 직렬화 된 객체를 반환 할 수도 있습니다.

web.config를 통해 제공 :

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

추가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/


@veggerby "아무것도하지 않고 내 세션을 유지하는 더미 HTTP 처리기로". 세션을 유지하기 위해 HTTP 핸들러의 샘플 코드를 게시 해 주시겠습니까?
Gopinath

아니요, 유일한 옵션은 세션 시간 초과를 늘리는 것입니다.하지만 장기적으로 보면 그것은 아마도 나쁜 생각 일 것입니다
veggerby

관련 문제를 조사 중이던 중이 솔루션을 발견했습니다. 좋은 물건. 하지만 사용자가 브라우저를 열어두고 PC가 10 시간 동안 절전 모드로 전환되지 않는다고하면 세션이 그렇게 오래 유지됩니다. 이게 옳은 거니?
Julius A

2
훌륭했지만 캐시 버스트를 호출에 추가하기 전까지는 실패했습니다. 이 캐시 버스트 매개 변수가 없으면 컨트롤러가 처음으로 호출됩니다
jean

1
@stom은 시간 제한이나 그 어떤 것도 아닌 세션 값을 의미 합니다. 사용 이유 DateTime.Now는 세션이 하트 비트를 통해 마지막으로 업데이트 된시기를 명확히하기 위해서입니다.
veggerby

69

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()", 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필요없이 외부에서 호출해야하는 유일한 것이므로 내보내기 만하면 됩니다. 이 : 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

세션을 유지해야합니까 (데이터가 있습니까?) 아니면 요청이 들어올 때 세션을 다시 인스턴스화하여이를 위조 할 수 있습니까? 첫 번째 인 경우 위의 방법을 사용하십시오. 두 번째 경우 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 웹 인터페이스와 SharePoint는 이러한 기능을 사용하는 것 같습니다. 오래된 페이지의 링크를 클릭하면 팝업 창에 인증 프롬프트가 표시되지만 명령 만 사용하면 작동합니다.


2

이 코드를 자바 스크립트 파일에 작성할 수 있습니다.

$(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)

왜 이것이 반대표를 받았습니까? 내가 언급하지 않은 문제가 있습니까? 그렇다면 미래의 독자가 알 수 있도록 공유하십시오!
피터

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에 Dialog를 추가하는 것을 잊지 마십시오.

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

첫째, setTimeout은 한 번만 실행되는 반면 setInterval은 반복적으로 실행됩니다. 두 번째로, heartbeat ()를 문자열처럼 호출하는 것은 저에게 효과가 없었지만 실제 함수처럼 호출했습니다.

그리고 저는이 솔루션이 Plesk에서 5 분 apppool 세션을 강제하는 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 분)을 연장합니다. 실제 웹 페이지 내용은 브라우저에 의해 삭제됩니다.

이를 수행하는 대안이며 아마도 더 깔끔한 방법은 새 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.