很多人並不知道 ASP.NET 的 Session 其實是有毒的!所以我個人會盡一切可能避免使用到 Session 機制,以免頁面遭到鎖定(Lock)狀況,影響使用者操作體驗。這篇文章我打算分享如何在 .NET Framework 的 ASP.NET MVC 5 精準控制不同 Controller 下的 Session 運作機制,避免使用者在多頁籤瀏覽的情況下遭到 Session 鎖定而無法瀏覽網頁。
針對全站關閉 Session 機制
首先,我們在 Web.config
的 <system.web>
區段內,就算你看不到 <sessionState mode="InProc" />
設定,但 .NET Framework 從某個版本開始預設就是啟用 sessionState 機制的,但你也可以透過以下設定明確關閉全站的 Session 機制:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.8" />
<sessionState mode="Off" />
</system.web>
</configuration>
不過,關閉 Session 之後,我們在 ASP.NET MVC 5 的 Session
與 TempData
物件就再也無法使用,只要執行到有用到這兩個物件的 Action 都會導致網站發生例外狀況!
針對特定 Controller 關閉 Session 機制
如果你現有的網站已經使用了大量的 Session 機制,但有一些需要長時間執行的頁面(例如匯出報表檔案),那就可以特別獨立一個 Controller
出來,特別對這個 Controller
關閉 Session 機制,如此一來就不會影響使用者瀏覽其他頁面的操作體驗。
只要在 Controller
類別上套用 [SessionState]
Filter 並傳入 SessionStateBehavior.Disabled
就可以停用整個 Controller
的 Session 使用:
[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
不過你依然要注意,這個 Controller
中所有 Action
都不能使用到 Session
與 TempData
物件!
針對特定 Controller 啟用 Session 的 ReadOnly (唯讀) 機制
如果你真的一定需要用到 Session 機制,但又不想讓使用者被 Session 鎖定,此時你可以把特定 Controller
設定為「唯讀」狀態,你可以讀取到 Session 資料,但又同時不會進入 Session 的鎖定狀態!👍
以下是在 Controller
中設定為 SessionStateBehavior.ReadOnly
唯讀模式的方法:
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
調整 TempData 使用 Cookies 來儲存暫存資料
由於 ASP.NET MVC 5 的 TempData
預設採用 Session 來實作,所以如果你真的一定要使用 TempData
但又不想使用有毒的 Session
的話,那就可以自行實作 ITempDataProvider 介面,改用 Cookies
來儲存資料!
注意: 從 ASP.NET Core 1.1 開始就有內建一個 CookieTempDataProvider 實作,但在 ASP.NET MVC 5 就要自行實作這個類別!
我有發現一個有趣的地方是,在 ASP.NET MVC 5 原始碼專案中並沒有發現 CookieTempDataProvider
的影子,但在 mono
計畫中 (一個跨平台的 .NET Framework 實作),卻有實作出一個 CookieTempDataProvider 類別,你可以從 GitHub 看到完整的實作原始碼!
你可以自行將該 CookieTempDataProvider
類別複製到你現有的 ASP.NET MVC 5 專案中,並在 Controller
或自訂的 BaseController
中覆寫 Initialize()
方法,替換掉預設的 TempDataProvider
屬性即可!如下範例:
public abstract class BaseController : Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
TempDataProvider = new CookieTempDataProvider(requestContext.HttpContext);
}
}
相關連結