[英]HttpContext.Session contains keys in one environment but not the other
[英]Added keys missing from HttpContext.Session (concurrency)
我正在使用.NET Core 3.1 。 我想知道HttpContext.Session.SetString(...)
是否是線程安全的? 例如,客戶端同時向同一個 controller 操作( Test
)發出兩個請求。 Controller 將字符串添加到 session(參見下面的示例)。 最后 session 中是否會有兩個、一個或零鍵(例如,當我刷新頁面時)?
public IActionResult Test()
{
HttpContext.Session.SetString(Guid.NewGuid().ToString(), "test");
return Ok();
}
使用DevExtreme FileUploader時,我將一些值保存到 session 。 當我一次上傳多個文件時,組件同時發出多個請求,最后, session 通常缺少一些鍵。 我認為有一些比賽條件正在發生。
添加:客戶代碼
我注意到 session 鍵僅在我使用method: 'POST'
(只有 1 個鍵)。 如果我使用method: 'GET'
,則有 3 個鍵(正確)。
$(document).ready(function () {
var method = 'GET'; // works (3 keys)
//var method = 'POST'; // doesn't work (1 key)
$('#fire').on('click', function () {
$.when(
$.ajax({
url: 'Session/Test',
method: method,
success: function(){
console.log('response', 1);
}
}),
$.ajax({
url: 'Session/Test',
method: method,
success: function(){
console.log('response', 2);
}
}),
$.ajax({
url: 'Session/Test',
method: method,
success: function(){
console.log('response', 3);
}
})
).then(function () {
alert('Done');
});
});
});
假設您使用 ASP.Net Core 提供的默認 session 實現。
就HttpContext.Session
而言:
HttpContext.Session
返回一個DistributedSession
的實例,它在內部使用Dictionary<TKey, TValaue>
。 字典不是線程安全的,因此如果您從多個線程(例如Task.Run
)訪問Session
,可能會導致意外結果。
對於不同請求的 Session 而言:
在 ASP.Net Core 中, Session
來自ISessionStore
,它具有短暫的生命周期。 意思是,請求不共享Session
object 。 所以如果你有並發請求,每個請求都有自己的Session
object。
在比賽條件方面:
The default implementation of session reads/writes session state from/to .AspNetCore.Session
cookie. 這可能會導致競爭條件。
因為Session
是每個客戶端的,所以當您有來自同一客戶端的並發請求觸及同一 cookie 中的相同位和部分時,您可能會遇到競爭條件 / session state 。 然而,競爭條件不是因為服務器端的Session
。 它實際上是由客戶端的 cookie 管理引起的。
Session state 是非鎖定的。 如果兩個請求同時嘗試修改 session 的內容,則最后一個請求將覆蓋第一個請求。
考慮這個例子:
Say you have a controller action which sets Session
with provided value
, and another controller action retrieves the value from Session
and returns it in body:
[HttpGet]
[Route("create")]
public IActionResult CreateSession([FromQuery]string value)
{
HttpContext.Session.SetString("key", value);
return Ok();
}
[HttpGet]
[Route("get")]
public IActionResult ReturnSession([FromQuery] string expected)
{
var actual = HttpContext.Session.GetString("key");
return Ok(new { actual, expected });
}
如果您使用HttpClient
測試這些操作:
async Task TestSession(HttpClient client, string str)
{
await client.GetAsync($"https://localhost:5001/session/create?value={str}");
var r = await client.GetAsync($"https://localhost:5001/session/get?expected={str}");
var session = await r.Content.ReadAsStringAsync();
Console.WriteLine(session);
}
using (var client = new HttpClient())
{
await TestSession(client, "abc");
}
output 應如下所示:
{"actual":"abc","expected":"abc"}
當您有來自同一客戶端的並發請求時會出現問題:
using (var client = new HttpClient())
{
var tasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
var str = i.ToString();
tasks.Add(Task.Run(() => TestSession(client, str)));
}
await Task.WhenAll(tasks);
}
output 看起來像:
{"actual":"2","expected":"1"}
{"actual":"3","expected":"6"}
{"actual":"4","expected":"5"}
{"actual":"4","expected":"3"}
{"actual":"4","expected":"2"}
{"actual":"8","expected":"4"}
{"actual":"7","expected":"8"}
{"actual":"7","expected":"7"}
{"actual":"9","expected":"0"}
{"actual":"9","expected":"9"}
In the above case, session state was changed by request 3 , between create and get of request 6 , meaning it is likely request 6 cannot see its session state correctly.
為避免此問題,您可以為每個批次使用不同的HttpClient
。
不,dotnet collections 不是線程安全的,session 也不是。 如果您在多個線程上共享相同的 session,則應將其視為只讀
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.