- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
所以,首先是免责声明——我是异步编程的新手。因此,在我开始实现我当前的项目之前,我一直在运行一系列测试来解决问题并更好地了解整个事情。
我今天遇到了一个与 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/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!