簡體   English   中英

ASP.Net會議

[英]ASP.Net Session

我想存儲用戶在一系列不同的ASP.Net webforms中執行的某些操作的“狀態”。 我對持久狀態的選擇有哪些,每種解決方案的優缺點是什么?

我一直在使用Session對象,並使用一些幫助方法來強類型化對象:

    public static Account GetCurrentAccount(HttpSessionState session)
    {
        return (Account)session[ACCOUNT];
    }

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }

很多消息來源都告訴我“會話是邪惡的”,所以這才是這個問題的根本原因。 我想知道你認為什么是“最佳實踐”,以及為什么。

會話狀態沒有任何本質上的邪惡。

有幾件事要記住,可能會咬你:

  1. 如果用戶按下瀏覽器后退按鈕,則返回上一頁,但不會還原會話狀態。 因此,您的CurrentAccount可能不是它最初在頁面上的內容。
  2. ASP.NET進程可以被IIS回收。 當發生這種情況時,您下一個請求將啟動一個新進程。 如果您正在使用進程會話狀態,默認情況下,它將會消失:-(
  3. 如果用戶在一段時間內不活動,則會話也可以使用相同的結果超時。 默認為20分鍾,所以午餐會很好。
  4. 使用進程外會話狀態要求存儲在會話狀態中的所有對象都是可序列化的。
  5. 如果用戶打開第二個瀏覽器窗口,他將期望擁有第二個不同的應用程序,但會話狀態最有可能在兩個之間共享。 因此,在一個瀏覽器窗口中更改CurrentAccount將在另一個瀏覽器窗口中執行相同操作。

臨時存儲表單數據的兩個選擇是,首先,將每個表單的信息存儲在會話狀態變量中;其次,使用URL參數傳遞表單信息。 使用Cookie作為潛在的第三種選擇根本不可行,原因很簡單,因為許多訪問者可能關閉了cookie(但這不會影響會話cookie)。 此外,我假設您的問題的性質,您不希望將此信息存儲在數據庫表中,直到它完全提交。

使用Session變量是解決此問題的經典解決方案,但它確實存在一些缺點。 其中包括(1)如果使用inproc會話管理,大量數據可能耗盡服務器RAM,(2)在服務器場中的多個服務器之間共享會話變量需要額外考慮,(3)專業設計的應用程序必須防止會話到期(不要只是轉換會話變量並使用它 - 如果會話已過期,則轉換會拋出錯誤)。 但是,對於絕大多數應用程序來說,會話​​變量無疑是最佳選擇。

另一種方法是在URL中傳遞每個表單的信息。 這種方法的主要問題是你必須非常小心“傳遞”信息。 例如,如果您要收集四頁信息,則需要先收集信息,然后將URL傳遞到第二頁,您必須將其存儲在該頁面的視圖狀態中。 然后,當調用第三頁時,您將從第二頁收集表單數據加上視圖狀態變量,並在URL等中進行編碼。如果您有五個或更多頁面,或者訪問者將在網站上跳轉,那么你手上會弄得一團糟。 還要記住,所有信息都需要A)被序列化為URL安全字符串,並且B)以防止基於URL的簡單黑客的方式編碼(例如,如果您將價格放在明文中並通過它一起,有人可以改變價格)。 請注意,您可以通過創建一種“會話管理器”來減少其中一些問題,並讓它為您管理URL字符串,但您仍然必須對任何給定鏈接可能會吹走某人整個會話的可能性非常敏感。它沒有妥善管理。

最后,我使用URL變量僅用於將非常有限的數據從一個頁面傳遞到下一個頁面(例如,在該項目的鏈接中編碼的項目ID)。

那么,讓我們假設您確實使用內置的Sessions功能管理用戶的數據。 為什么有人會告訴你“會話是邪惡的”? 好吧,除了上面提到的內存負載,服務器場和到期考慮因素之外,對Session變量的主要批評是,它們是有效的無類型變量。

幸運的是,謹慎使用Session變量可以避免內存問題(無論如何都應該在數據庫中保存大項),如果運行的站點足夠大,需要服務器場,那么有很多機制可用於共享內置於ASP的狀態.NET(提示:您不會使用inproc存儲)。

為了避免幾乎所有Session的其余缺點,我建議實現一個對象來保存會話數據以及一些簡單的Session對象管理功能。 然后將它們構建為Page類的后代,並將這個后代Page類用於所有頁面。 然后,通過頁面類作為一組強類型值訪問Session數據是一件簡單的事情。 請注意,對象的字段將為您提供一種以強類型方式訪問每個“會話變量”的方法(例如,每個變量一個字段)。

如果這對您來說是一項簡單的任務,或者您想要一些示例代碼,請告訴我們!

據我所知, Session是存儲此信息的預期方式。 請記住,會話狀態通常默認存儲在進程中。 如果您有多個Web服務器,或者如果重新啟動IIS,則會丟失會話狀態。 這可以通過使用ASP.NET狀態服務甚至SQL數據庫來存儲會話來解決。 這可以確保人們恢復會話,即使他們被重新路由到不同的Web服務器,也可以回收工作進程。

至於“會話是邪惡的”......如果你在使用經典ASP開發我不得不同意,但ASP.NET / IIS做得更好。

真正的問題是維持國家的最佳方式是什么。 在我們的例子中,當涉及到當前登錄用戶時,我們將該對象存儲在Session中,因為我們經常在其中引用它們的名稱,電子郵件地址,授權等等。

不需要任何長期持久性的信息,其他的小花絮 ,我們使用cookie和視圖狀態的組合。

其聲名狼借的原因之一是,匆忙的開發人員過度使用UI代碼中的字符串文字(而不是像你的幫助類)作為項目鍵,並最終得到了一大堆不可測試的混雜狀態。 某種包裝是非邪惡會話使用的入門級要求。

如果要存儲可在Web應用程序中全局訪問的信息,則執行此操作的方法是ThreadStatic屬性。 這會將Classstatic成員轉換為當前線程共享的成員,而不是其他線程。 ThreadStatic的優點是您不必擁有Web上下文。 例如,如果你的后端不引用System.Web ,但也希望在那里共享信息,你可以在ThreadStatic屬性中的每個請求的開頭設置用戶的id ,並在你的依賴項中引用它而不用需要訪問Session對象。

因為它是static但僅限於一個線程,我們確保其他同時訪問者不會收到我們的會話。 只要您確保為每個請求重置屬性,這都可以。 這使它成為cookie的理想伴侶。

我認為在這種情況下使用Session對象是正常的,但你應該記住,如果長時間沒有瀏覽器活動,Session會過期( HttpSessionState.Timeout屬性確定會話狀態提供者終止會話的時間),所以最好是返回前檢查值是否存在:

public static Account GetCurrentAccount(HttpSessionState session)
{
    if (Session[ACCOUNT]!=null)
        return (Account)Session[ACCOUNT];
    else
        throw new Exception("Can't get current account. Session expired.");
}

短期信息,只需要存活到下一個請求,也可以存儲在ViewState 這意味着對象被序列化並存儲在發送到瀏覽器的頁面中,然后在點擊事件或類似事件上將其發布回服務器。 然后, ViewState被解碼並再次轉換為對象,隨時可以檢索。

會話不是邪惡的,它們在ASP.NET應用程序中起着重要的作用,提供必須在用戶的“會話”期間在多個頁面之間共享的數據。 有一些建議,我會說盡可能使用SQL Session管理,並確保您在會話集合中使用的對象是“可序列化的”。 最佳實踐是在絕對需要跨頁面共享狀態信息時使用會話對象,並且在不需要時不使用它。 客戶端無法獲得該信息,會話密鑰保存在cookie中,或通過查詢字符串保存,或者根據其配置方式使用其他方法,然后會話對象在數據庫表中可用(除非您使用InProc,在這種情況下,您的會話將有可能在重新加載網站時被吹走,或者在大多數群集環境中幾乎無用)。

會話為邪惡:不在ASP.NET中,正確配置。 是的,盡可能無國籍是理想的,但現實是你無法從這里到達那里。 但是,您可以使Session以減少其影響的方式運行 - 特別是StateServer或數據庫會話。

我認為“邪惡”來自過度使用會話。 如果你只是在其中粘貼任何東西(比如使用全局變量),你最終會遇到性能不佳而且一團糟。

除非已清除,否則您在會話對象中放置的任何內容都將在會話期間保留。 使用inproc和stateserver存儲的內存管理不善將迫使您在必要時提前擴展。 在會話中僅存儲會話/用戶的ID,並使用幫助程序類按需將所需內容加載到緩存對象中。 這樣,您可以根據我們使用的數據的頻率來微調它的生命周期。 asp.net的下一個版本可能有分布式緩存(謠言)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM