ASP.NET Core中間件會(huì)話狀態(tài)讀寫及生命周期示例
前言:
本文使用 .NET Core SDK 3.1 的版本。
1) 關(guān)于Http中的會(huì)話
- Http是一種采用請(qǐng)求響應(yīng)消息交換模式,且無(wú)狀態(tài)的傳輸協(xié)議。
- 該協(xié)議確保客戶端將請(qǐng)求報(bào)文發(fā)送給目標(biāo)服務(wù)器并接收來(lái)自服務(wù)端的響應(yīng)報(bào)文,這個(gè)報(bào)文交換是一個(gè)Http事務(wù)。
- 從協(xié)議的角度講,即使在使用長(zhǎng)連接的情況下,同一個(gè)客戶端和服務(wù)器之間進(jìn)行多個(gè)Http事務(wù)也是完全獨(dú)立的
- 所以需要在應(yīng)用層為兩者去建立一個(gè)上下文來(lái)保存多次消息交換的狀態(tài),這就是所謂的會(huì)話。
2) 關(guān)于 ASP.NET Core 中的會(huì)話
- 在 ASP.NET Core 中利用一個(gè)叫做 Session 的中間件來(lái)實(shí)現(xiàn)會(huì)話,
- 每個(gè)會(huì)話都有一個(gè)標(biāo)識(shí)SessionKey,但是SessionKey不是唯一標(biāo)識(shí),是一個(gè)數(shù)據(jù)字典的形式,
- 將SessionKey保存在服務(wù)端,當(dāng)會(huì)話中間件在處理會(huì)話的第一個(gè)請(qǐng)求的時(shí)候,會(huì)創(chuàng)建一個(gè)SessionKey
- 并基于它創(chuàng)建一個(gè)獨(dú)立的數(shù)據(jù)字典來(lái)存儲(chǔ)會(huì)話狀態(tài),應(yīng)用程序設(shè)置的會(huì)話狀態(tài)都是自動(dòng)保存在當(dāng)前會(huì)話對(duì)應(yīng)的數(shù)據(jù)字典中的
- 這個(gè)SessionKey最終會(huì)以 Cookie 的形式寫入響應(yīng)并返回給客戶端,
- 客戶端在每次發(fā)起請(qǐng)求的時(shí)候都會(huì)附加這個(gè) Cookie,從而使我們的應(yīng)用程序能夠準(zhǔn)確定位到當(dāng)前會(huì)話對(duì)應(yīng)的數(shù)據(jù)字典。
一、配置會(huì)話中間件
配置基于內(nèi)存的分布式緩存服務(wù)和會(huì)話服務(wù),如需要將緩存放置于數(shù)據(jù)庫(kù)可以參考微軟官方文檔
public void ConfigureServices(IServiceCollection services)
{
// 添加基于內(nèi)存的緩存服務(wù),以供會(huì)話中間件來(lái)使用
collection.AddDistributedMemoryCache();
// 添加會(huì)話
collection.AddSession();
}
添加會(huì)話中間件
public void Configure(IApplicationBuilder app)
{
// 引入會(huì)話中間件
app.UseSession();
}
二、會(huì)話狀態(tài)的讀寫
寫入Session
ISession session = httpContext.Session;
var sessionStartTime = DateTime.Now.ToString(CultureInfo.InvariantCulture);
session.SetString("SessionStartTime", sessionStartTime);
讀取Session
ISession session = httpContext.Session;
session.TryGetValue("SessionStartTime", out var value);
var sessionStartTime = Encoding.UTF8.GetString(value);
獲取SessionId
ISession session = httpContext.Session;
session.TryGetValue("SessionStartTime", out var value);
var sessionStartTime = Encoding.UTF8.GetString(value);
獲取SessionKey
SessionKey 需要通過(guò)反射獲取
ISession session = httpContext.Session;
var field = typeof(DistributedSession).GetTypeInfo()
.GetField("_sessionKey", BindingFlags.Instance | BindingFlags.NonPublic);
var sessionKey = field?.GetValue(session);
三、 示例的生命周期
這里準(zhǔn)備了示例的代碼:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/get", async httpContext =>
{
ISession session = httpContext.Session;
string sessionStartTime;
if (session.TryGetValue("SessionStartTime", out var value))
{
sessionStartTime = Encoding.UTF8.GetString(value);
}
else
{
sessionStartTime = DateTime.Now.ToString(CultureInfo.InvariantCulture);
session.SetString("SessionStartTime", sessionStartTime);
}
var field = typeof(DistributedSession).GetTypeInfo()
.GetField("_sessionKey", BindingFlags.Instance | BindingFlags.NonPublic);
var sessionKey = field?.GetValue(session);
var responseText = $@"
<html>
<body>
<h1>Get Session</h1>
<ul>
<li>Session ID:{session.Id}</li>
<li>Session Key:{sessionKey}</li>
<li>Session Start Time:{sessionStartTime}</li>
<li>Current Time:{DateTime.Now:yyyy-MM-dd HH:mm:ss}</li>
</ul>
</body>
</html>";
httpContext.Response.ContentType = "text/html";
await httpContext.Response.WriteAsync(responseText);
});
});
清除瀏覽器中的 Cookie,然后刷新頁(yè)面進(jìn)入/get頁(yè)面中,可以看到在新的網(wǎng)絡(luò)請(qǐng)求中響應(yīng)標(biāo)頭多了一個(gè) set-cookie,這個(gè)set-cookie是被加密的SessionKey,還具有 httponly 的標(biāo)簽,以防止Cookie 的值被跨站讀取。
默認(rèn)請(qǐng)求下 Cookie 采用的路徑是根路徑
然后我們重新刷新頁(yè)面,可以看到請(qǐng)求標(biāo)頭中多出一個(gè) cookie,就是之前的 set-cookie,因?yàn)橹熬彺姹磺宄院?,第一次刷新?biāo)頭多一個(gè) set-cookie,相當(dāng)于創(chuàng)建一個(gè)新的會(huì)話,當(dāng)下一次發(fā)起請(qǐng)求就會(huì)帶上 cookie。
四、其他
- SessionId 可以作為會(huì)話的唯一標(biāo)識(shí),但是 SessionKey 不可以
- 也就是說(shuō)兩個(gè)不同的 Session,肯定具有不同的 SessionId,但是他們有可能共享相同的SessionKey
- 當(dāng)會(huì)話中間件接收到會(huì)話的第一個(gè)請(qǐng)求的時(shí)候,他會(huì)創(chuàng)建兩個(gè)不同的 guid,分別表示 SessionKey 和 SessionId
- 其中 SessionId 將被作為會(huì)話狀態(tài)的一部分被存儲(chǔ)起來(lái),而 SessionKey 則會(huì)以會(huì)話的形式返回給客戶端
- 會(huì)話一般都是有有效期的,而會(huì)話的有效期基本決定了存儲(chǔ)的會(huì)話狀態(tài)數(shù)據(jù)的有效期
- 默認(rèn)情況下 ASP.NET Core 應(yīng)用的會(huì)話它所采用的默認(rèn)過(guò)期時(shí)間是20分鐘, 默認(rèn)情況下20分鐘內(nèi)的任意請(qǐng)求都會(huì)將會(huì)話的壽命延長(zhǎng)再延長(zhǎng)
- 兩次請(qǐng)求的時(shí)間超過(guò)了有效期,意味著這個(gè)會(huì)話過(guò)期,存儲(chǔ)的會(huì)話狀態(tài)數(shù)據(jù)包括 SessionId 也都會(huì)被清除
- 但是請(qǐng)求攜帶的 SessionKey 可能還是原來(lái)的 SessionKey
- 在這種請(qǐng)求下,會(huì)話中間件會(huì)創(chuàng)建一個(gè)新的會(huì)話,這個(gè)新的會(huì)話具有不同的 SessionId,但是整個(gè)會(huì)話狀態(tài)仍然會(huì)沿用原來(lái)的 SessionKey
- 所以 SessionKey 不能作為會(huì)話的唯一標(biāo)識(shí),它只代表存儲(chǔ)數(shù)據(jù)的標(biāo)識(shí)
- 會(huì)話本質(zhì)上就是在應(yīng)用的層面上提供了一個(gè)數(shù)據(jù)容器來(lái)保存客戶端的狀態(tài),這個(gè)客戶端狀態(tài)就是會(huì)話狀態(tài),會(huì)話的核心功能就是會(huì)話狀態(tài)的讀寫
以上就是ASP.NET Core中間件會(huì)話狀態(tài)讀寫及生命周期示例的詳細(xì)內(nèi)容,更多關(guān)于ASP.NET Core會(huì)話中間件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于asp.net MVC 應(yīng)用程序的生命周期(詳解)
下面小編就為大家分享一篇基于asp.net MVC 應(yīng)用程序的生命周期詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
?ASP.NET Core 模型驗(yàn)證過(guò)濾器的兩種實(shí)現(xiàn)方法
?在.Net Core的時(shí)代中,框架會(huì)幫你自動(dòng)驗(yàn)證,本文主要介紹了?ASP.NET Core 模型驗(yàn)證過(guò)濾器的兩種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
asp.net和ajax實(shí)現(xiàn)智能搜索功能代碼
近來(lái)一直在開(kāi)發(fā)股票模擬系統(tǒng),終于告一段落了,回想起來(lái)感慨很多。突然想應(yīng)該做點(diǎn)總結(jié)了,想來(lái)想去還是覺(jué)得通過(guò)寫點(diǎn)日志來(lái)把相關(guān)的知識(shí)點(diǎn)記錄下來(lái),下面就我在項(xiàng)目中經(jīng)常用到的動(dòng)態(tài)提示搜索選項(xiàng)功能的實(shí)現(xiàn)。2010-03-03
asp.net結(jié)合aspnetpager使用SQL2005的存儲(chǔ)過(guò)程分頁(yè)
項(xiàng)目中用到了,同事阿春寫了例子,并在實(shí)際項(xiàng)目中使用了,記錄下。感謝春哥的無(wú)私奉獻(xiàn)。2009-07-07
ASP.NET項(xiàng)目開(kāi)發(fā)中日期控件DatePicker如何使用
這篇文章主要為大家詳細(xì)介紹了ASP.NET項(xiàng)目開(kāi)發(fā)中日期控件DatePicker的使用方法,感興趣的小伙伴們可以參考一下2016-04-04
ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html
ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html...2006-09-09
gridview中實(shí)現(xiàn)radiobutton的單選示例
radiobutton可以單選,于是想讓gridview也可以實(shí)現(xiàn),具體的思路及代碼如下,感興趣的朋友可以參考下2013-08-08
在.NET Core控制臺(tái)程序中如何使用依賴注入詳解
這篇文章主要給大家介紹了關(guān)于在.NET Core控制臺(tái)程序中如何使用依賴注入的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10

