ASP.NET Oturumunu Açık / Canlı Tutma


116

Kullanıcı tarayıcı penceresi açık olduğu sürece bir ASP.NET oturumunu canlı tutmanın en kolay ve en göze batmayan yolu hangisidir? AJAX çağrıları zamanlanmış mı? Aşağıdakileri önlemek istiyorum: bazen kullanıcılar pencerelerini uzun süre açık tutuyor, sonra bir şeyler giriyor ve sunucu tarafı oturumunun süresi dolduğu için artık hiçbir şey çalışmıyor. Kapalı oturumların (tarayıcı penceresini kapatarak) hızlı zaman aşımına uğramasını istediğim için sunucuda zaman aşımı değerini 10 dakikadan fazla artırmak istemiyorum.

Öneriler, kod örnekleri?


Yanıt almak için bu bağlantıyı kontrol edebilirsiniz dotnetcurry.com/ShowArticle.aspx?ID=453
Geliştirici

Yanıtlar:


171

Oturumumu canlı tutmaktan başka hiçbir şey yapmayan sahte bir HTTP İşleyicisine basit bir AJAX çağrısı gerçekleştirmek için JQuery kullanıyorum:

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

Oturum işleyici şu kadar basit olabilir:

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

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

Anahtar, IRequiresSessionState'i eklemektir, aksi takdirde Session kullanılamaz (= null). İşleyici, tabii ki, çağıran JavaScript'e bazı verilerin döndürülmesi gerekiyorsa, bir JSON serileştirilmiş nesne de döndürebilir.

Web.config aracılığıyla kullanıma sunulmuştur:

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

katma gelen balexandre 2012 14 Ağustos'ta

Bu örnekten o kadar çok hoşlandım ki, HTML / CSS ve vuruş bölümü ile geliştirmek istiyorum.

bunu değiştir

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

içine

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

ve Ekle

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

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

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

işte sadece dayak kısmı için canlı bir örnek : http://jsbin.com/ibagob/1/


@veggerby "Oturumumu canlı tutan hiçbir şey yapmayan sahte bir HTTP İşleyicisine". Oturumu canlı tutmak için HTTP İşleyicisinin örnek kodunu gönderebilir misiniz?
Gopinath

hayır, ve oradaki tek seçeneğiniz (sanırım) oturum zaman aşımını artırmak, ancak bu muhtemelen uzun vadede kötü bir fikir
vegger

Konuyla ilgili araştırmalar yapıyordu ve bu çözüme rastladı. İyi şeyler. Yine de bir sorgu, eğer kullanıcı tarayıcısını açık bırakırsa ve bilgisayarın 10 saat uyku moduna geçmediğini söylerse, oturum bu kadar uzun süre canlı tutulur, değil mi? Bu doğru mu?
Julius A

2
İyi iş ama aramaya bir önbellek patlaması ekleyene kadar başarısız oldu. Bu önbellek patlama parametresi olmadan denetleyici ilk kez çağrılır
jean

1
@stom , bir zaman aşımı veya herhangi bir şey değil, bir oturum değeri anlamına gelir . Kullanmanın nedeni DateTime.Nowsadece oturumun kalp atışı yoluyla en son ne zaman güncellendiğini göstermekti.
vegger

69

ASP.NET MVC kullanıyorsanız - ek bir HTTP işleyicisine ve web.config dosyasında bazı değişikliklere ihtiyacınız yoktur. İhtiyacınız olan tek şey - sadece bir Ana / Ortak denetleyiciye basit bir işlem eklemek için:

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

, bunun gibi bir JavaScript kodu yazın (bunu sitenin JavaScript dosyalarından birine koydum):

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

ve bir JavaScript işlevi çağırarak bu işlevi başlatın:

SetupSessionUpdater('/Home/KeepSessionAlive');

Lütfen aklınızda bulundurun! Bu işlevi yalnızca yetkili kullanıcılar için uyguladım (çoğu durumda misafirler için oturum durumunu korumak için bir neden yoktur) ve oturum durumunu etkin tutma kararı yalnızca buna bağlı değildir - tarayıcının açık olup olmadığı, ancak yetkili kullanıcının bazı etkinlikler yapması gerekir sitede (bir fareyi hareket ettirin veya bir tuş yazın).


3
MVC için bunun daha iyi bir cevap olduğunu düşünüyorum. .Ashx dosyasını kullanmanıza gerek yok, neden yapayım?
arame3333

Asp mvc'deki HTTP İşleyicisi ile bunu kontrol edin , umut birine yardımcı olur.
shaijut

3
Maryan, ayrıca @Url.Action("KeepSessionAlive","Home")başlatıcı işlevinde kullanmak isteyebilirsin, böylece URL'yi sabit kodlaman ve ayrıca bir IIFE'nin içine ilk bloğu atmana gerek kalmaz ve sadece dışarı aktarırsın SetupSessionUpdaterçünkü harici olarak çağrılması gereken tek şey budur - gibi bir şey this: SessionUpdater.js
KyleMit

SetInterval'in kullanılmamasının bir nedeni var mı? setInterval(KeepSessionAlive, 300000)
Matthieu Cormier

8

Sunucuya her istekte bulunduğunuzda, oturum zaman aşımı sıfırlanır. Böylece, sunucudaki boş bir HTTP işleyicisine bir ajax çağrısı yapabilirsiniz, ancak işleyicinin önbelleğinin devre dışı bırakıldığından emin olun, aksi takdirde tarayıcı işleyicinizi önbelleğe alır ve yeni bir istekte bulunmaz.

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 - Oturumda değişkenleri depolamanın ek yüküne gerek yoktur. Sadece sunucuya bir talepte bulunmak yeterlidir.


2

Oturumu gerçekten tutmanız gerekiyor mu (içinde verileriniz var mı?) Veya bir istek geldiğinde oturumu yeniden başlatarak bunu taklit etmek yeterli mi? İlki ise, yukarıdaki yöntemi kullanın. İkincisi ise, Session_End olay işleyicisini kullanmak gibi bir şey deneyin.

Form Kimlik Doğrulaması'na sahipseniz, Global.asax.cs içinde aşağıdaki gibi bir şey alırsınız:

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

Ve bilet ömrünü oturum süresinden çok daha uzun süre ayarlarsınız. Kimlik doğrulaması yapmıyorsanız veya farklı bir kimlik doğrulama yöntemi kullanıyorsanız, benzer numaralar vardır. Microsoft TFS web arayüzü ve SharePoint bunları kullanıyor gibi görünüyor - eski bir sayfadaki bir bağlantıya tıklarsanız, açılır pencerede kimlik doğrulama istemleri alırsınız, ancak yalnızca bir komut kullanırsanız çalışır.


2

bu kodu java script dosyanıza yazabilirsiniz.

$(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*1000O oturum zaman aşımı süresini yenilenir, yenileme zamanıdır. Yenileme zaman aşımı, iis = 20 dakika üzerinden varsayılan süre olarak hesaplanır, 20 × 60000 = 1200000 milisaniye - 60000 milisaniye (oturumun sona ermesinden bir dakika önce) 1140000 olduğu anlamına gelir.


0

İstemci bilgisayar uyku moduna geçtiğinde hayatta kalması gereken alternatif bir çözüm.

Çok sayıda oturum açmış kullanıcınız varsa, bunu dikkatli kullanın, çünkü bu çok fazla sunucu belleği tüketebilir.

Giriş yaptıktan sonra (bunu giriş kontrolünün LoggedIn olayında yapıyorum)

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)

Bu neden reddedildi? onunla ilgili bahsetmediğim bir sorun var mı? durum böyleyse lütfen paylaşın ki gelecekteki okuyucular bundan haberdar olsun!
Peter

0

Birkaç günümü, kullanıcıya oturumu yenileme veya süresinin dolmasına izin veren bir açılır iletişim kutusu aracılığıyla WebForms'ta bir kullanıcı oturumunun nasıl uzatılacağını anlamaya çalışarak geçirdim. Bilmeniz gereken 1 numaralı şey, diğer yanıtların bazılarında bu süslü 'HttpContext' şeylerinin hiçbirine ihtiyacınız olmadığıdır. Tek ihtiyacınız olan jQuery'nin $ .post (); yöntem. Örneğin, hata ayıklarken şunu kullandım:

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

ve canlı sitenizde şunun gibi bir şey kullanırsınız:

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

Bu kadar kolay. Ayrıca, kullanıcıya oturumunu yenileme seçeneği sunmak isterseniz aşağıdakine benzer bir şey yapın:

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

Diyaloğu html'nize eklemeyi unutmayın:

        <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'nin çözümü ile ilgili olarak, bir VB uygulamasında uygulamaya çalışıyorsanız, sağlanan kodu bir çevirmen aracılığıyla çalıştırmaya çalışırken dikkatli olun. Aşağıdakiler işe yarayacak:

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

Ayrıca, heartbeat () gibi çağırmak yerine şu işlevi görür:

 setTimeout("heartbeat()", 300000);

Bunun yerine, şöyle adlandırın:

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

Birincisi, setTimeout yalnızca bir kez tetiklenirken setInterval tekrar tekrar tetiklenir. İkincisi, heartbeat () işlevini bir dizge gibi çağırmak benim için işe yaramadı, oysa onu gerçek bir işlev gibi çağırmak benim için çalışmadı.

Ve bu çözümün GoDaddy'nin Plesk'te 5 dakikalık bir uygulama havuzu oturumunu zorlama yönündeki saçma kararının üstesinden geleceğini kesinlikle% 100 onaylayabilirim!


0

İşte tutamak optimizasyonu ile Maryan çözümünün JQuery eklenti sürümü. Yalnızca JQuery 1.7+ ile!

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

ve * .cshtml dosyanıza nasıl aktarılır

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

0

[Partiye geç ...]

Bunu bir Ajax çağrısı veya WebService işleyicisinin ek yükü olmadan yapmanın başka bir yolu, belirli bir süre sonra (yani, genellikle 20 dakika olan oturum durumu zaman aşımından önce) özel bir ASPX sayfası yüklemektir:

// 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.aspxSayfada yalnızca başka bir şey dokunuş yapan boş sayfası / yenilemek Sessiondurumu:

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

Bu, bir img(görüntü) öğesi oluşturarak ve tarayıcıyı içeriğini KeepAlive.aspxsayfadan yüklemeye zorlayarak çalışır . Bu sayfanın yüklenmesi, sunucunun Sessionnesneye dokunmasına (güncellemesine) neden olarak oturumun sona erme kayan zaman penceresini uzatır (tipik olarak 20 dakika daha). Gerçek web sayfası içeriği tarayıcı tarafından atılır.

Bunu yapmanın alternatif ve belki de daha temiz bir yolu, yeni bir iframeöğe oluşturmak ve KeepAlive.aspxsayfayı buna yüklemektir . iframeEleman böyle it a gizli bir alt öğesi yaparak olarak, gizlenmiştir divsayfadaki eleman yerde.

Sayfanın kendisindeki etkinlik, tüm sayfa gövdesi için fare ve klavye eylemleri kesilerek tespit edilebilir:

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

Bu fikirden pay alamam; bkz: https://www.codeproject.com/Articles/227382/Alert-Session-Time-out-in-ASP-Net .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.