gpt4 book ai didi

c# - RedisSessionProvider 和异步方法

转载 作者:可可西里 更新时间:2023-11-01 11:16:59 28 4
gpt4 key购买 nike

所以,首先是免责声明——我是异步编程的新手。因此,在我开始实现我当前的项目之前,我一直在运行一系列测试来解决问题并更好地了解整个事情。

我今天遇到了一个与 HttpContext.Current.Session 为 null 有关的问题,这恰好遍布我当前的代码库。

这是我的小测试应用程序:

public partial class RandomTests : System.Web.UI.Page
{
protected async void Page_Load(object sender, EventArgs e)
{
Debug.WriteLine("----------------------------------------------------------------------------------");
Debug.WriteLine("Blend dual call start");
Debug.WriteLine("Operation complete. Returned: " + await BlendDualCall() + " at " + DateTime.Now.ToString("mm':'ss':'fff"));
Debug.WriteLine("Blend dual call complete");
Debug.WriteLine("----------------------------------------------------------------------------------");
}

public async Task<string> BlendDualCall()
{
var cTask = Task.Run(() => YLogin(1000));
var fTask = Task.Run(() => FLogin(2000));

Debug.WriteLine("Awaiting results.");
var yResult = await cTask;
Debug.WriteLine("YLogin result returned at " + DateTime.Now.ToString("mm':'ss':'fff"));
var fResult = await fTask;
Debug.WriteLine("FLogin result returned at " + DateTime.Now.ToString("mm':'ss':'fff"));

return yResult + " " + fResult;
}

#region Non-Async Methods

public string FLogin(int waitTime)
{
Debug.WriteLine("FLogin process executed on thread id: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(waitTime);

//Session is null here
return HttpContext.Current.Session.SessionID + "_" + Thread.CurrentThread.ManagedThreadId;
}

public string YLogin(int waitTime)
{
Debug.WriteLine("YLogin process executed on thread id: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(waitTime);

//Session is not null here (System.Web.SessionState.HttpSessionState). Whats the difference?
return Session.SessionID + "_" + Thread.CurrentThread.ManagedThreadId;
}

#endregion
}

web.config 中的自定义 SessionState 提供程序:

<sessionState mode="Custom" customProvider="RedisSessionProvider">
<providers>
<add name="RedisSessionProvider" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="******" port="***" accessKey="********" ssl="true" />
</providers>
</sessionState>

我正在寻找一些关于 SessionState 发生了什么以及为什么它在异步调用中为 null 的理解。有趣的是,HttpContext.Current.Session.SessionID 为空但 Session.SessionID 不为空,我怀疑它使用的是不同的 SessionState 提供程序?关于该主题,重要的是要注意我使用 RedisSessionProvider 作为自定义 SessionState 提供程序(用于 Azure)。我需要对 RedisSessionProvider 做些什么才能让它处理异步调用吗?有人能给我指出正确的方向吗?也许可以简单解释一下 SessionState 如何处理异步调用?

TIA

最佳答案

session 不能同时跨多个线程共享。这是所有 ASP.NET session 的限制,而不仅仅是 Redis session 。

核心问题是Task.Run的使用。 Task.Run 将使 ASP.NET 每个请求使用 多个 线程,这是一个非常糟糕的主意,因为它会严重影响您的可伸缩性。 Task.Run 还明确地跳出请求上下文,因此 HttpContext.Current 将为 null - 这是设计使然。

最好的解决方案是删除对 Task.Run 的所有调用。您可以很好地执行多个并发异步操作 - 如果它们实际上是异步的(不仅仅是在后台线程上运行)。例如:

// True asynchronous calls
public async Task<string> FLogin(int waitTime)
{
await Task.Delay(waitTime);
return HttpContext.Current.Session.SessionID + "_" + Thread.CurrentThread.ManagedThreadId;
}

public async Task<string> BlendDualCall()
{
var cTask = YLogin(1000);
var fTask = FLogin(2000);
...
}

如果它们不是真正的异步,那么下一个最佳解决方案是一次执行一个。例如:

public string FLogin(int waitTime);
public string BlendDualCall()
{
var yResult = YLogin(1000);
var fResult = FLogin(2000);
...
}

如果您绝对必须在服务器上执行并行代码(同样,我真的不推荐这样做),那么您需要在开始之前从 session 中提取所有需要的数据并行工作。例如:

public string FLogin(int waitTime, string sessionId)
{
Thread.Sleep(waitTime);
return sessionID + "_" + Thread.CurrentThread.ManagedThreadId;
}
public string BlendDualCall()
{
var sessionId = HttpContext.Current.Session.SessionID.ToString();
var cTask = Task.Run(() => YLogin(1000, sessionId));
var fTask = Task.Run(() => FLogin(2000, sessionId));
...
}

关于c# - RedisSessionProvider 和异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45495902/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com