第十六節:Asp.Net Core中Session的使用、擴展、進程外Session


一. 簡介

   關於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 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM