一. 簡介
關於Session的原理可參照Asp.Net版本Session的文章,去查閱。
1. 普通用法
(1).通過Nuget引入【Microsoft.AspNetCore.Http】程序集,Core Mvc中已經默認引入了,在哪使用using一下即可。
(2).注入Session相關的服務。
A:在ConfigureService注冊基於服務器內存的Session, services.AddDistributedMemoryCache(); services.AddSession(); 在Configure中進行啟用Session,app.UseSession();
注:一定要在mvc前面進行注入,進程外Session的注入后面介紹。
B:如果項目中使用了CookiePolicyOptions,一定要將里面true改為false,如: options.CheckConsentNeeded = context => false; 或者配置Session的性質,options.Cookie.IsEssential = true;(表示cookie是必須的),否則chrome中拿不到Session值
解釋:這是個GDRP條例,讓用戶自己選擇使用用cookie,詳見 http://www.zhibin.org/archives/667 或 https://www.cnblogs.com/GuZhenYin/p/9154447.html
C:在控制器中通過 HttpContext.Session 來向Session中讀寫各種值。
注冊和啟用相關的代碼:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.Configure<CookiePolicyOptions>(options => 4 { 5 // This lambda determines whether user consent for non-essential cookies is needed for a given request. 6 options.CheckConsentNeeded = context => false; //改為false或者直接注釋掉,上面的Session才能正常使用 7 options.MinimumSameSitePolicy = SameSiteMode.None; 8 }); 9 //注冊Session服務 10 //基於內存的Session 11 services.AddDistributedMemoryCache(); 12 //默認過期時間為20分鍾,每次訪問都會重置 13 services.AddSession(); 14 15 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 16 } 17 public void Configure(IApplicationBuilder app, IHostingEnvironment env) 18 { 19 if (env.IsDevelopment()) 20 { 21 app.UseDeveloperExceptionPage(); 22 } 23 else 24 { 25 app.UseExceptionHandler("/Home/Error"); 26 } 27 app.UseStaticFiles(); 28 app.UseCookiePolicy(); 29 //啟用Session管道 30 app.UseSession(); 31 32 app.UseMvc(routes => 33 { 34 routes.MapRoute( 35 name: "default", 36 template: "{controller=CoreSession}/{action=Index6}/{id?}"); 37 }); 38 }
測試代碼:
1 public IActionResult Index() 2 { 3 string userName = HttpContext.Session.GetString("userName"); 4 if (string.IsNullOrEmpty(userName)) 5 { 6 userName = "ypf"; 7 HttpContext.Session.SetString("userName", userName); 8 } 9 var t1 = HttpContext.Session.GetString("userName"); 10 ViewBag.userName = userName; 11 return View(); 12 } 13 14 public IActionResult Index2() 15 { 16 string userName = HttpContext.Session.GetString("userName"); 17 ViewBag.userName = userName; 18 return View(); 19 }
補充Session默認提供的方法:
2. 全局注冊使用
(1).背景:通常便於管理,我們將Session進行全局統一注入,方便管理。
(2).步驟:
A: 在普通用法的前提下,在ConfigureService中進行統一對象的注冊, services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
B:在控制器利用構造函數進行注入。
C:正常使用即可,案例詳見項目的Index3和Index4
代碼分享:
1 public class CoreSessionController : Controller 2 { 3 private readonly IHttpContextAccessor httpContextAccessor; 4 5 private ISession MySession => httpContextAccessor.HttpContext.Session; 6 7 public CoreSessionController(IHttpContextAccessor httpContextAccessor) 8 { 9 this.httpContextAccessor = httpContextAccessor; 10 } 11 #region 02-測試統一注入的用法 12 /// <summary> 13 /// 下面是統一注入使用的寫法 14 /// </summary> 15 /// <returns></returns> 16 17 public IActionResult Index3() 18 { 19 string userName = MySession.GetString("userName"); 20 if (string.IsNullOrEmpty(userName)) 21 { 22 userName = "ypf"; 23 MySession.SetString("userName", userName); 24 } 25 var t1 = MySession.GetString("userName"); 26 ViewBag.userName = userName; 27 return View(); 28 } 29 30 public IActionResult Index4() 31 { 32 string userName = MySession.GetString("userName"); 33 ViewBag.userName = userName; 34 return View(); 35 } 36 #endregion 37 38 }
二. 高級
1. Session的擴展
(1).背景
我們發現系統默認提供的Session方法,僅能存儲byte、string、int類型,很不靈活,我們想能存儲任何對象,這個時候就需要我們自行擴展。 對SessionExtensions類進行擴展
(2).利用Newtonsoft.Json進行擴展
A. 擴展代碼詳見SessionExtensions中的Set和Get方法
B. 案例詳見Index5
(3).利用protobuf-net進行擴展
A. 通過Nuget安裝程序集【protobuf-net】,這是谷歌的一個程序集,序列化和反序列效率更高
B. 擴展代碼詳見SessionExtensions中的Set2和Get2方法, 如果寫入的是個類,類名上要加 [ProtoContract],屬性上要加 [ProtoMember(1)] [ProtoMember(2)]等等, 如:UserInfor2
C. 案例詳見Index6
擴展代碼:
1 public static class SessionExtensions 2 { 3 #region 01-利用Newtonsoft.Json進行擴展 4 public static void Set<T>(this ISession session, string key, T value) 5 { 6 session.SetString(key, JsonConvert.SerializeObject(value)); 7 } 8 9 public static T Get<T>(this ISession session, string key) 10 { 11 var value = session.GetString(key); 12 return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value); 13 } 14 #endregion 15 16 #region 02-利用protobuf-net進行擴展 17 public static void Set2<T>(this ISession session, string key, T value) 18 { 19 using (MemoryStream stream = new MemoryStream()) 20 { 21 Serializer.Serialize(stream, value); 22 byte[] byteArrary = stream.ToArray(); 23 session.Set(key, byteArrary); 24 } 25 } 26 27 public static T Get2<T>(this ISession session, string key) 28 { 29 byte[] byteArray = session.Get(key); 30 if (byteArray == null) 31 { 32 return default(T); 33 } 34 else 35 { 36 using (MemoryStream stream = new MemoryStream(byteArray)) 37 { 38 return Serializer.Deserialize<T>(stream); 39 } 40 } 41 } 42 #endregion 43 }
類代碼:
1 public class UserInfor1 2 { 3 public string id { get; set; } 4 public string userName { get; set; } 5 } 6 [ProtoContract] 7 public class UserInfor2 8 { 9 [ProtoMember(1)] 10 public string id { get; set; } 11 [ProtoMember(2)] 12 public string userName { get; set; } 13 14 }
測試代碼:
1 #region 03-測試Newtonsoft.Json進行擴展 2 public IActionResult Index5() 3 { 4 UserInfor1 user = HttpContext.Session.Get<UserInfor1>("u1"); 5 if (user == null) 6 { 7 user = new UserInfor1(); 8 user.id = "001"; 9 user.userName = "Marren"; 10 HttpContext.Session.Set<UserInfor1>("u1", user); 11 } 12 ViewBag.id = user.id; 13 ViewBag.userName = user.userName; 14 return View(); 15 } 16 #endregion 17 18 #region 04-測試protobuf-net進行擴展 19 public IActionResult Index6() 20 { 21 UserInfor2 user = HttpContext.Session.Get2<UserInfor2>("u2"); 22 if (user == null) 23 { 24 user = new UserInfor2(); 25 user.id = "001"; 26 user.userName = "Marren"; 27 HttpContext.Session.Set2<UserInfor2>("u2", user); 28 } 29 ViewBag.id = user.id; 30 ViewBag.userName = user.userName; 31 return View(); 32 } 33 #endregion
2.Session的性質
(1). Session的過期時間(多次訪問將會被重置,默認過期時間為20分鍾)
如:options.IdleTimeout = TimeSpan.FromMinutes(120);
(2). 設置為true表示前端js等腳本無法讀取cookie,防止了xss攻擊(默認是true)
如:options.Cookie.HttpOnly = true;
(3). Cookie是必須的(默認是false),可以覆蓋上面的cookie策略
如:options.Cookie.IsEssential = true;
3. 如何在普通類中使用Session對象?
(1).說明
再普通類中如何調用Session,大約有兩種思路:以構造函數的注入進去,但是如果這個類不是過濾器,使用的時候就需要實例化,又需要傳入對象進去,如CheckLogin類,很麻煩,所以建議用第二種方案,直接吧實例好的Session傳入進去,直接使用即可,如CheckLogin2.
(2). 方案一
先統一注入, services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();,然后再在控制器中進行構造函數注入,但調用的時候還需要傳入進去。
PS:過濾器中可以直接context.httpContext.Session來設置
(3). 方案二
直接把實例好的Session傳進去
1 public class CheckLogin2 2 { 3 private ISession MySession { get; set; } 4 5 public CheckLogin2(ISession mySession) 6 { 7 MySession = mySession; 8 } 9 public bool isLogin() 10 { 11 string userName = MySession.GetString("userName"); 12 if (string.IsNullOrEmpty(userName)) 13 { 14 return false; 15 } 16 return true; 17 } 18 }
三. 進程外Session
關於進程外Session的好處、解決了什么痛點問題,可以參考Asp.Net 中的進程外Session,去查閱。 (解決了IIS重啟Session丟失的問題,解決了Session空間有限容易被擠爆的問題,但不能解決瀏覽器重啟找不到Session的問題!)
特別說明:基於SQLServer或Redis數據的進程外Session 的數據庫方面的配置和前面分布式緩存章節數據庫的配置完全相同,去查閱。
1. 基於SQLServer
(1). 安裝【Microsoft.Extensions.Caching.SqlServer】程序集,如果是Core MVC程序,自帶的Microsoft.AspNetCore.App包里已經涵蓋了該程序集,無需重復安裝。
(2). 首先要有個目標數據庫中(比如CacheDB數據庫),然后以管理員身份cmd運行下面指令,會創建一張名叫“AspNetCoreSession”表,相應的Session信息都存在於這張表中。
【dotnet sql-cache create "Server=localhost;User=sa;Password=123456;Database=CacheDB" dbo AspNetCoreSession】成功后會提示:Table and index were created successfully.
PS:補充表的結構和含義, 分別是鍵、值、到期時刻(有問題)、滑動過期時間、絕對過期時間。
(3). 將原先基於內存的Session代碼( services.AddDistributedMemoryCache(); )替換成基於SqlServer的代碼,如下:
1 //01-基於內存的Session 2 //services.AddDistributedMemoryCache(); 3 4 //02-基於SQLServer的Session 5 services.AddDistributedSqlServerCache(options => 6 { 7 options.ConnectionString = Configuration["SqlSeverConnectionString"]; 8 options.SchemaName = "dbo"; 9 options.TableName = "AspNetCoreSession"; 10 });
1 { 2 "Logging": { 3 "LogLevel": { 4 "Default": "Warning" 5 } 6 }, 7 "AllowedHosts": "*", 8 "SqlSeverConnectionString": "Server=localhost;User=sa;Password=123456;Database=CacheDB" 9 }
(4). 其它的配置都不變,正常使用即可。
2. 基於Redis
(1). 安裝【Microsoft.Extensions.Caching.StackExchangeRedis】程序集,Core MVC中這個也是不包含的。
(2). 下載Redis程序,打開redis-server.exe,啟動Redis。
(3). 將原先基於內存的Session代碼 ( services.AddDistributedMemoryCache(); ) 替換成基於Redis的代碼,如下:
//01-基於內存的Session //services.AddDistributedMemoryCache(); //03-基於Redis的Session services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost"; options.InstanceName = "SampleInstance"; });
(4). 其它配置都不變,正常使用即可。
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。