Menjaga Sesi ASP.NET Terbuka / Hidup

116

Manakah cara termudah dan paling tidak mengganggu untuk menjaga sesi ASP.NET tetap hidup selama pengguna membuka jendela browser? Apakah itu panggilan AJAX berjangka waktu? Saya ingin mencegah hal berikut: terkadang pengguna membiarkan jendelanya terbuka untuk waktu yang lama, lalu memasukkan barang, dan saat mengirimkan tidak ada yang berfungsi lagi karena sesi sisi server kedaluwarsa. Saya tidak ingin meningkatkan nilai batas waktu selama lebih dari 10 menit di server karena saya ingin sesi tertutup (dengan menutup jendela browser) untuk waktu habis dengan cepat.

Saran, contoh kode?

Alex
sumber
Anda dapat memeriksa tautan ini untuk mendapatkan jawaban juga dotnetcurry.com/ShowArticle.aspx?ID=453
Pengembang

Jawaban:

171

Saya menggunakan JQuery untuk melakukan panggilan AJAX sederhana ke Handler HTTP tiruan yang tidak melakukan apa pun selain menjaga Sesi saya tetap hidup:

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

Penangan sesi bisa sesederhana:

public class SessionHeartbeatHttpHandler : IHttpHandler, IRequiresSessionState
{
    public bool IsReusable { get { return false; } }

    public void ProcessRequest(HttpContext context)
    {
        context.Session["Heartbeat"] = DateTime.Now;
    }
}

Kuncinya adalah menambahkan IRequiresSessionState, jika tidak Sesi tidak akan tersedia (= null). Penangan tentu saja juga dapat mengembalikan objek serial JSON jika beberapa data harus dikembalikan ke JavaScript pemanggil.

Tersedia melalui web.config:

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

ditambahkan dari balexandre pada 14 Agustus 2012

Saya sangat menyukai contoh ini, sehingga saya ingin meningkatkan dengan HTML / CSS dan bagian beat

ubah ini

//$("#heartbeat").show().fadeOut(1000); // just a little "red flash" in the corner :)

ke

beatHeart(2); // just a little "red flash" in the corner :)

dan tambahkan

// 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 dan CSS

<div class="heartbeat">&hearts;</div>

/* HEARBEAT */
.heartbeat {
    position: absolute;
    display: none;
    margin: 5px;
    color: red;
    right: 0;
    top: 0;
}

berikut adalah contoh langsung hanya untuk bagian pemukulan: http://jsbin.com/ibagob/1/

veggerby
sumber
@veggerby "ke Handler HTTP tiruan yang tidak melakukan apa pun kecuali membuat Sesi saya tetap hidup". Bisakah Anda memposting kode contoh HTTP Handler agar sesi tetap aktif?
Gopinath
tidak, dan satu-satunya pilihan Anda di sana (saya kira) adalah meningkatkan batas waktu sesi, tetapi itu mungkin ide yang buruk dalam jangka panjang
veggerby
Sedang melakukan investigasi tentang masalah terkait dan menemukan solusi ini. Barang bagus. Namun satu pertanyaan, jika pengguna meninggalkan browser mereka terbuka, dan mengatakan pc tidak tidur selama 10 jam, sesi akan tetap hidup selama itu, bukan? Apakah ini benar?
Julius A
2
Kerja bagus tapi gagal sampai saya menambahkan cache burst ke panggilan. Tanpa parameter cache burst ini, pengontrol dipanggil pertama kali
jean
1
@stom itu dimaksudkan untuk menjadi nilai sesi, bukan waktu tunggu atau apa pun. Alasan penggunaan DateTime.Nowhanya untuk membuatnya jelas kapan sesi terakhir diperbarui melalui detak jantung.
veggerby
69

Jika Anda menggunakan ASP.NET MVC - Anda tidak memerlukan penangan HTTP tambahan dan beberapa modifikasi pada file web.config. Yang Anda butuhkan - cukup tambahkan beberapa tindakan sederhana di pengontrol Rumah / Umum:

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

, tulis kode JavaScript seperti ini (saya telah meletakkannya di salah satu file JavaScript situs):

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

, dan menginisialisasi fungsionalitas ini dengan memanggil fungsi JavaScript:

SetupSessionUpdater('/Home/KeepSessionAlive');

Tolong dicatat! Saya telah menerapkan fungsi ini hanya untuk pengguna yang berwenang (dalam banyak kasus tidak ada alasan untuk mempertahankan status sesi untuk tamu) dan keputusan untuk tetap mengaktifkan status sesi tidak hanya berdasarkan - apakah browser terbuka atau tidak, tetapi pengguna yang berwenang harus melakukan beberapa aktivitas di situs (gerakkan mouse atau ketik beberapa tombol).

Maryan
sumber
3
Untuk MVC saya pikir ini adalah jawaban yang lebih baik. Tidak perlu menggunakan file .ashx, mengapa Anda?
arame3333
Dengan HTTP Handler di asp mvc periksa ini , semoga bisa membantu seseorang.
shaijut
3
Maryan, Anda mungkin juga ingin menggunakan @Url.Action("KeepSessionAlive","Home")fungsi penginisialisasi sehingga Anda tidak perlu melakukan hardcode URL dan juga membuang blok pertama di dalam IIFE dan hanya mengekspornya SetupSessionUpdaterkarena itulah satu-satunya hal yang perlu dipanggil secara eksternal - sesuatu seperti ini: SessionUpdater.js
KyleMit
Apakah ada alasan mengapa setInterval tidak digunakan? setInterval(KeepSessionAlive, 300000)
Matthieu Cormier
8

Setiap kali Anda membuat permintaan ke server, batas waktu sesi disetel ulang. Jadi Anda bisa membuat panggilan ajax ke penangan HTTP kosong di server, tapi pastikan cache penangan dinonaktifkan, jika tidak browser akan men-cache penangan Anda dan tidak akan membuat permintaan baru.

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 - Tidak perlu overhead penyimpanan variabel dalam sesi. Hanya melakukan permintaan terlebih dahulu ke server sudah cukup.

BornToCode
sumber
2

Apakah Anda benar-benar perlu mempertahankan sesi (apakah Anda memiliki data di dalamnya?) Atau apakah cukup untuk memalsukan ini dengan memulihkan sesi saat ada permintaan? Kalau dulu, gunakan cara di atas. Jika yang kedua, coba sesuatu seperti menggunakan event handler Session_End.

Jika Anda memiliki Autentikasi Formulir, maka Anda mendapatkan sesuatu di Global.asax.cs seperti

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

Dan Anda menetapkan masa pakai tiket lebih lama dari masa pakai sesi. Jika Anda tidak mengautentikasi, atau menggunakan metode autentikasi yang berbeda, ada trik serupa. Antarmuka web Microsoft TFS dan SharePoint tampaknya menggunakan ini - manfaatnya adalah jika Anda mengklik tautan pada halaman basi, Anda mendapatkan petunjuk otentikasi di jendela popup, tetapi jika Anda hanya menggunakan perintah, itu berfungsi.

Henry Troup
sumber
2

Anda bisa menulis kode ini di file java script itu saja.

$(document).ready(function () {
        var delay = (20-1)*60*1000;
        window.setInterval(function () {
            var url = 'put the url of some Dummy page';
            $.get(url);                
        }, delay);
});

Waktu (20-1)*60*1000penyegaran, itu akan menyegarkan waktu tunggu sesi. Refresh timeout dihitung sebagai waktu default keluar dari iis = 20 menit, berarti 20 × 60000 = 1200000 milidetik - 60000 milidetik (Satu menit sebelum sesi berakhir) adalah 1140000.

ANKIT KISHOR
sumber
0

Berikut adalah solusi alternatif yang akan bertahan jika pc klien masuk ke mode tidur.

Jika Anda memiliki sejumlah besar pengguna yang login, gunakan ini dengan hati-hati karena ini dapat memakan banyak memori server.

Setelah Anda masuk (saya melakukan ini di acara LoggedIn pada kontrol login)

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
sumber
Mengapa ini ditolak? apakah ada masalah yang belum saya sebutkan? jika itu masalahnya, silakan bagikan sehingga pembaca di masa mendatang menyadarinya!
Peter
0

Saya menghabiskan beberapa hari mencoba mencari cara untuk memperpanjang sesi pengguna di WebForms melalui dialog popup yang memberi pengguna opsi untuk memperbarui sesi atau membiarkannya berakhir. Hal # 1 yang perlu Anda ketahui adalah bahwa Anda tidak memerlukan hal-hal 'HttpContext' yang mewah ini terjadi di beberapa jawaban lainnya. Yang Anda butuhkan hanyalah $ .post () dari jQuery; metode. Misalnya, saat men-debug saya menggunakan:

$.post("http://localhost:5562/Members/Location/Default.aspx");

dan di situs langsung Anda, Anda akan menggunakan sesuatu seperti:

$.post("http://mysite/Members/Location/Default.aspx");

Semudah itu. Selain itu, jika Anda ingin meminta pengguna dengan opsi untuk memperbarui sesi mereka, lakukan sesuatu yang mirip dengan berikut ini:

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

Jangan lupa untuk menambahkan Dialog ke html Anda:

        <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>
Colin
sumber
0

Berkenaan dengan solusi veggerby, jika Anda mencoba menerapkannya di aplikasi VB, berhati-hatilah saat mencoba menjalankan kode yang disediakan melalui penerjemah. Berikut ini akan bekerja:

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

Selain itu, alih-alih memanggil fungsi seperti heartbeat ():

 setTimeout("heartbeat()", 300000);

Sebaliknya, sebut saja seperti:

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

Pertama, setTimeout hanya diaktifkan sekali sedangkan setInterval akan diaktifkan berulang kali. Kedua, memanggil detak jantung () seperti string tidak berfungsi untuk saya, sedangkan memanggilnya seperti fungsi sebenarnya.

Dan saya benar-benar dapat 100% mengonfirmasi bahwa solusi ini akan mengatasi keputusan konyol GoDaddy untuk memaksakan sesi apppool 5 menit di Plesk!

ShowJX1990
sumber
0

Berikut versi plugin JQuery dari solusi Maryan dengan pengoptimalan pegangan. Hanya dengan 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)

dan bagaimana hal itu mengimpor di * .cshtml Anda

$('body').heartbeat(); // Simple
$('body').heartbeat({url:'@Url.Action("Home", "heartbeat")'}); // different url
$('body').heartbeat({every:6*60*1000}); // different timeout
AlexPalla
sumber
0

[Terlambat ke pesta ...]

Cara lain untuk melakukan ini tanpa overhead panggilan Ajax atau penangan WebService adalah dengan memuat halaman ASPX khusus setelah jangka waktu tertentu (yaitu, sebelum batas waktu status sesi, yang biasanya 20 menit):

// Client-side JavaScript
function pingServer() {
    // Force the loading of a keep-alive ASPX page
    var img = new Image(1, 1);
    img.src = '/KeepAlive.aspx';
}

The KeepAlive.aspxhalaman hanyalah sebuah halaman kosong yang tidak apa-apa tapi sentuhan / refresh Sessionnegara:

// 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;
    }
}

Ini bekerja dengan membuat elemen img(gambar) dan memaksa browser untuk memuat kontennya dari KeepAlive.aspxhalaman. Memuat halaman itu menyebabkan server menyentuh (memperbarui)Session objek, memperpanjang jendela waktu geser kedaluwarsa sesi (biasanya 20 menit lagi). Konten halaman web yang sebenarnya dibuang oleh browser.

Cara alternatif, dan mungkin lebih bersih, untuk melakukannya adalah dengan membuat iframeelemen baru dan memuat KeepAlive.aspxhalaman ke dalamnya. The iframeelemen tersembunyi, seperti dengan membuat elemen anak dari tersembunyidiv elemen di suatu tempat pada halaman.

Aktivitas di halaman itu sendiri dapat dideteksi dengan mencegat tindakan mouse dan keyboard untuk seluruh badan halaman:

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

Saya tidak bisa mengambil pujian untuk ide ini; lihat: https://www.codeproject.com/Articles/227382/Alert-Session-Time-out-in-ASP-Net .

David R Tribble
sumber