การรักษา ASP.NET Session Open / Alive


116

วิธีใดเป็นวิธีที่ง่ายที่สุดและไม่เป็นการรบกวนที่สุดในการทำให้เซสชัน ASP.NET คงอยู่ตราบเท่าที่ผู้ใช้เปิดหน้าต่างเบราว์เซอร์ไว้ AJAX โทรตามเวลาหรือไม่ ฉันต้องการป้องกันสิ่งต่อไปนี้: บางครั้งผู้ใช้เปิดหน้าต่างไว้เป็นเวลานานจากนั้นป้อนข้อมูลและเมื่อส่งแล้วจะไม่มีอะไรทำงานอีกต่อไปเนื่องจากเซสชันฝั่งเซิร์ฟเวอร์หมดอายุ ฉันไม่ต้องการเพิ่มค่าการหมดเวลานานกว่า 10 นาทีบนเซิร์ฟเวอร์เนื่องจากฉันต้องการให้เซสชันปิด (โดยการปิดหน้าต่างเบราว์เซอร์) เพื่อให้หมดเวลาอย่างรวดเร็ว

ข้อเสนอแนะตัวอย่างโค้ด?


คุณสามารถตรวจสอบลิงค์นี้เพื่อรับคำตอบเช่นกันdotnetcurry.com/ShowArticle.aspx?ID=453
พัฒนา

คำตอบ:


171

ฉันใช้ 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) แน่นอนว่าตัวจัดการสามารถส่งคืนอ็อบเจ็กต์ที่ทำให้เป็นอนุกรม JSON ได้หากข้อมูลบางอย่างควรถูกส่งกลับไปยัง JavaScript ที่เรียกใช้

เผยแพร่ผ่าน web.config:

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

เพิ่มจากbalexandreเมื่อวันที่ 14 สิงหาคม 2555

ฉันชอบตัวอย่างนี้มากจนฉันต้องการปรับปรุงด้วย 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 Handler เพื่อให้เซสชันมีชีวิตอยู่ได้ไหม
ปินาถ

ไม่และทางเลือกเดียวของคุณที่นั่น (ฉันเดา) คือการเพิ่มระยะหมดเวลาของเซสชัน แต่นั่นอาจเป็นความคิดที่ไม่ดีในระยะยาว
veggerby

กำลังดำเนินการตรวจสอบปัญหาที่เกี่ยวข้องและพบวิธีแก้ปัญหานี้ สิ่งที่ดี. แม้ว่าคำถามหนึ่งข้อหากผู้ใช้เปิดเบราว์เซอร์ทิ้งไว้และบอกว่าพีซีไม่เข้าสู่โหมดสลีปเป็นเวลา 10 ชั่วโมงเซสชันจะยังคงมีชีวิตอยู่เป็นเวลานานใช่มั้ย? นี่ใช่มั้ย?
Julius A

2
ทำได้ดี แต่ฉันล้มเหลวจนกว่าฉันจะเพิ่มการระเบิดของแคชในการโทร หากไม่มีพารามิเตอร์ cache burst นี้คอนโทรลเลอร์จะถูกเรียกเป็นครั้งแรก
ยีน

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 ของไซต์):

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 ฉันคิดว่านี่คือคำตอบที่ดีกว่า ไม่ต้องใช้ไฟล์. asx แล้วจะทำไม?
arame3333

ด้วยHTTP Handler ใน asp mvcตรวจสอบสิ่งนี้หวังว่าจะช่วยใครบางคนได้
shaijut

3
Maryan คุณอาจต้องการใช้@Url.Action("KeepSessionAlive","Home")ในฟังก์ชัน initializer เพื่อที่คุณจะได้ไม่ต้องฮาร์ดโค้ด URL และโยนบล็อกแรกเข้าไปใน IIFE และเพียงแค่ส่งออกSetupSessionUpdaterเนื่องจากนั่นเป็นสิ่งเดียวที่ต้องเรียกใช้จากภายนอกเช่น นี้: SessionUpdater.js
KyleMit

มีสาเหตุที่ไม่ใช้ setInterval หรือไม่? setInterval(KeepSessionAlive, 300000)
Matthieu Cormier

8

เมื่อใดก็ตามที่คุณร้องขอไปยังเซิร์ฟเวอร์การหมดเวลาเซสชันจะรีเซ็ต ดังนั้นคุณสามารถโทร ajax ไปยังตัวจัดการ HTTP ที่ว่างเปล่าบนเซิร์ฟเวอร์ได้ แต่ตรวจสอบให้แน่ใจว่าแคชของตัวจัดการถูกปิดใช้งานมิฉะนั้นเบราว์เซอร์จะแคชตัวจัดการของคุณและจะไม่ทำการร้องขอใหม่

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

คุณสามารถเขียนโค้ดนี้ในไฟล์ java script ของคุณได้

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


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)

เหตุใดจึงโหวตลง มีปัญหาบางอย่างที่ฉันไม่ได้กล่าวถึงหรือไม่? หากเป็นเช่นนั้นโปรดแบ่งปันเพื่อให้ผู้อ่านในอนาคตได้รับทราบ!
ปีเตอร์

0

ฉันใช้เวลาสองสามวันในการพยายามหาวิธียืดเวลาเซสชันผู้ใช้ใน WebForms ผ่านกล่องโต้ตอบป๊อปอัปให้ผู้ใช้มีตัวเลือกในการต่ออายุเซสชันหรืออนุญาตให้หมดอายุ สิ่งที่คุณต้องรู้อันดับ 1 ก็คือคุณไม่จำเป็นต้องมีสิ่งที่ 'HttpContext' แปลกใหม่เกิดขึ้นในคำตอบอื่น ๆ สิ่งที่คุณต้องมีคือ $ .post () ของ jQuery; วิธี. ตัวอย่างเช่นในขณะที่ดีบักฉันใช้:

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

สำหรับโซลูชันของ 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

นอกจากนี้แทนที่จะเรียกฟังก์ชัน like heartbeat () เช่น:

 setTimeout("heartbeat()", 300000);

ให้เรียกมันว่า:

 setInterval(function () { heartbeat(); }, 300000);

อันดับหนึ่ง setTimeout จะเริ่มทำงานเพียงครั้งเดียวในขณะที่ setInterval จะเริ่มทำงานซ้ำ ๆ หมายเลขสองการเรียก heartbeat () เหมือนสตริงไม่ได้ผลสำหรับฉันในขณะที่เรียกมันเหมือนฟังก์ชันจริง

และฉันสามารถยืนยันได้อย่างแน่นอน 100% ว่าโซลูชันนี้จะเอาชนะการตัดสินใจที่ไร้สาระของ GoDaddy ในการบังคับใช้เซสชันแอปพูล 5 นาทีใน Plesk!


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: 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 คือการโหลดหน้า ASPX พิเศษหลังจากระยะเวลาที่กำหนด (กล่าวคือก่อนหมดเวลาของสถานะเซสชันซึ่งโดยทั่วไปคือ 20 นาที):

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