The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

ASP.NET MVC 5 如何精準控制不同 Controller 下的 Session 運作機制

很多人並不知道 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 的 SessionTempData 物件就再也無法使用,只要執行到有用到這兩個物件的 Action 都會導致網站發生例外狀況!

Object reference not set to an instance of an object.

The SessionStateTempDataProvider class requires session state to be enabled.

針對特定 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 都不能使用到 SessionTempData 物件!

針對特定 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);
    }
}

相關連結

留言評論