[ASP.NET Core 6 MVC] 使用 Session
這篇是參考自 C# Corner : How To Use Sessions In ASP.NET Core 的教學,不過文中是 .NET 5,所以和 .NET 6 設定上有點差異,再加上和過去 .NET 4 使用 namespace 後就可以無腦使用 Session 不太一樣,就做了這個筆記,以下範例使用 Visual Studio 2022,建立專案為 ASP.NET Core Web 應用程式 (Model-View-Controller)使用 .NET 6.0 架構。
下載 Session 套件
在方案總管視窗對「相依性(Dependencies)」滑鼠右鍵,選擇「管理 NuGet 套件」:
在「瀏覽」標籤頁中搜尋「Session」,應該最多人下載的是 Microsoft 的「Microsoft.AspNetCore.Session」:
依版本點選「安裝」(這裡我選最新穩定版 2.2.0):
若有變更警告點選「OK」,授權提示點選「I Accept」:
裝好後剛剛的頁面應該會顯示目前版本,且原本的「安裝」變成「解除安裝」,就可以關掉 NuGet 分頁了。
設定 Program.cs
再來要設定 Program.cs 設定檔,至方案總管視窗雙擊此檔案:
原本檔案的最上面是:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); var app = builder.Build();
在此給容器加入 Session service:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddDistributedMemoryCache(); // 加入記憶體供 Session 使用 builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(1); // 設定 Session Expire 時間 }); var app = builder.Build(); app.UseSession(); // 加人 pipe line
使用 Session ,存取字串和整數
要利用 Session 存取字串可以使用 SetString() 和 GetString() 方法,而存取整數的是 SetInt32() 和 GetInt32(),方法在 HttpContext.Session 下,例如下面我用範本的 Home/Privacy 與 Home/ 兩個 Action 和 View,在 HomeController.cs 中的這兩個 Action 中加入以下程式碼:
namespace DemoSession.Controllers { public class HomeController : Controller { public IActionResult Privacy() { // 將這兩個值存入 Session,key 分別為 "Greeting" 和 ".NET" HttpContext.Session.SetString("Greeting", "Hello World!!!"); HttpContext.Session.SetInt32(".NET", 6); return View(); } public IActionResult Index() { // 從 Session 中用 key 取出數值,賦值給 ViewBag 帶往 View 去 ViewBag.Message = HttpContext.Session.GetString("Greeting"); ViewBag.Version = HttpContext.Session.GetInt32(".NET"); return View(); } } }
而 Index 的 View 加入從 ViewBag 取出的值:
<p> @ViewBag.Message <!-- 顯示從 Session 取出的字串 --> </p> <p> 此版本為 .NET @ViewBag.Version <!-- 顯示從 Session 取出的整數 --> </p>
執行應用程式,route 預設打開 Home/Index,會看到因為 ViewBag 的兩個變數都是空的,所以呈現缺項的檢視頁面:
如果點選範本提供的上方 Layout 中的「Privacy」連結,經過 Controller 的 Action 看到的 Privacy View :
檢視頁面沒有東西,因為我們也沒有修改他,點擊此頁是為了測試經過 Privacy 的 Action 時會做的,也就是將變數存入 Session ,這時再點擊上方的「Home」連結回到 Home/Index:
就會看到 Home/Index 出現 ViewBag 的兩個變數了,會有這兩個變數的原因是因為剛剛走過 Privacy 的 Action,在 Session 存入變數,然後在 Index 的 Action 從 Session 取出變數,賦予給 ViewBag ,使 Index 的 View 能夠呈現。
- HttpContext.Session.SetString(key, value) 存入字串
- HttpContext.Session.GetString(key) 取出字串
- HttpContext.Session.SetInt(key, value) 存入整數
- HttpContext.Session.GetInt(key) 取出整數
用 Json 序列化使 Session 存取物件
如果要存入 Session 的不只是字串和整數,可以利用 Newtonsoft 的 Json 序列化,首先要在 NuGet 管理套件下載 Newtonsoft.Json:
引用 Newtonsoft.Json 命名空間後,可使用 JsonConvert.SerializeObject(物件) 將物件轉成字串,使用 JsonConvert.DeserializeObject<類別>(字串) 將字串轉成相對應的物件。為了示範物件轉換,我在 ~/Models 寫了一個 Student.cs 類別,有字串、浮點數、日期的屬性與建構子:
namespace DemoSession.Models { public class Student { public string Name { get; set; } public double Height { get; set; } public string Major { get; set; } public DateTime Birthday { get; set; } public Student(string name, double height, string major, DateTime birthday) { Name = name; Height = height; Major = major; Birthday = birthday; } } }
而 HomeController.cs 在 Privacy Action 實體化一個 List,新增四個 Student 物件,將他序列化放進 Session 中,而 Index Action 將資料從 Session 取出來,一個是字串給 ViewBag.StudentsString,另一個反序列化轉回 List 物件,為了處理空值有一些判斷,但不是這篇的重點,轉成物件給 ViewBag.StudentObject:
using DemoSession.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; namespace DemoSession.Controllers { public class HomeController : Controller { public IActionResult Privacy() { // 實體化集合物件 List<Student> students = new List<Student>(); students.Add(new Student("May", 158.5, "ComputerScience", new DateTime(2005,5,5))); students.Add(new Student("Johnny", 184.0, "Mathematics", new DateTime(1997, 10, 24))); students.Add(new Student("Eddie", 181.0, "Biology", new DateTime(2000, 1, 28))); students.Add(new Student("Venom", 179.5, "Mathematics", new DateTime(1999, 7, 12))); // 將物件序列化成字串,以 "stuList" 為 key 存到 Session 中 HttpContext.Session.SetString("stuList", JsonConvert.SerializeObject(students)); return View(); } public IActionResult Index() { // 從 Session 以 "stuList" 為 key 取出字串資料 string StudentsString = HttpContext.Session.GetString("stuList"); ViewBag.StudentsString = StudentsString; // 若不為空值,將字串反序列化回集合物件 ViewBag.StudentsObject = string.IsNullOrEmpty(StudentsString) ? null : JsonConvert.DeserializeObject<List<Student>>(StudentsString); return View(); } } }
Index 的檢視中,將 Controller 帶過去的 ViewBag 資料顯示出來,一個是字串的 ViewBag.StudentsString,另一個是確定非空時用 foreach 遍尋出來用表格呈現的 ViewBag.StudentsObject,兩者都是來自 Session。index.cshtml 程式碼如下:
<p> 字串資料: @ViewBag.StudentsString </p> <p> <table class="table table-striped"> <tr> <th>Name</th> <th>Height</th> <th>Major</th> <th>Birthday</th> </tr> @{ if(ViewBag.StudentsObject != null) { foreach(Student student in ViewBag.StudentsObject) { <tr> <td>@student.Name</td> <td>@student.Height</td> <td>@student.Major</td> <td>@student.Birthday</td> </tr> } } } </table> </p>
執行應用程式,先到 Home/Index 是沒有東西的,此時 Session 還沒有資料:
點擊 Home/Privacy 再回到 Home/Index 就會因為 Session 有資料,使得 List<Student> 物件以表格呈現,成功在 Session 傳遞物件:
- Newtonsoft.Json.JsonConvert.SerializeObject(object) 序列化物件成字串
- Newtonosft.Json.JsonConvert.DeserializeObject<class>(string) 反序列化成物件
將序列化寫成擴充方法
可以將以上序列化及反序列化的方法寫成 HttpContext.Session 的靜態擴充方法,在專案新增一個資料夾 ~/Extensions/,新增一個類別 SessionExtension.cs,程式碼:
using Newtonsoft.Json; namespace DemoSession.Extensions { public static class SessionExtension { public static void SetObject<T>(this ISession session, string key, T value) { session.SetString(key, JsonConvert.SerializeObject(value)); } public static T GetObject<T>(this ISession session, string key) { var value = session.GetString(key); return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value); } } }
使用時就可直接 HttpContext.Session.SetObject<>() 與 GetObject<>():
using DemoSession.Models; using DemoSession.Extensions; namespace DemoSession.Controllers { public class HomeController : Controller { public IActionResult Index() { // 從 Session 中用 "stuList" 的 key 取出物件 ViewBag.StudentsObject = HttpContext.Session.GetObject<List<Student>>("stuList"); return View(); } public IActionResult Privacy() { List<Student> students = new List<Student>(); students.Add(new Student("May", 158.5, "ComputerScience", new DateTime(2005,5,5))); students.Add(new Student("Johnny", 184.0, "Mathematics", new DateTime(1997, 10, 24))); students.Add(new Student("Eddie", 181.0, "Biology", new DateTime(2000, 1, 28))); students.Add(new Student("Venom", 179.5, "Mathematics", new DateTime(1999, 7, 12))); // 將物件以 "stuList" 的 key 存入 Session HttpContext.Session.SetObject<List<Student>>("stuList", students); return View(); } } }
可更簡潔存取 Session 中的物件。
留言
張貼留言