我正在ASP.NET MVC控制器方法的上下文中研究async
和await
,并得到一些意外的行为。
我有以下控制器类:
[SessionState(System.Web.SessionState.SessionStateBehavior.Required)]
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> Check1()
{
Session["Test"] = "Check";
System.Diagnostics.Debug.WriteLine("Session: " + Session["Test"]);
await Task.Delay(20000);
return View();
}
public ActionResult Check2()
{
var test = Session["Test"];
ViewBag.Test = test;
return View();
}
}
每个方法的简单视图Check1和Check2:
检查1
@{
ViewBag.Title = "Check1";
}
<h2>View with Delay</h2>
检查2
@{
ViewBag.Title = "Check2";
var check = ViewBag.Test;
}
<h2>Immediate View @check</h2>
现在,在启动应用程序后,当我在一个选项卡中打开http://localhost:23131/Home/Check1
,在第二个选项卡上打开http://localhost:23131/Home/Check2
时,对Check1
的调用在20秒后按预期返回,对Check2
的调用立即返回,但它在会话状态下没有设置值,我不明白为什么。它应该立即设置,因为它在延迟之前。但是,正确的值会打印在输出窗口上。
现在,在Check1返回后,点击Check2
选项卡上的刷新会带来viewbag
中会话的值并显示它
之后,如果我再次刷新两个选项卡,则在Check1完成后(延迟20秒),Check2
不会返回,尽管Check2是async
。
我的问题是:
- 第一次打开两个选项卡时,由于
Check1
是async
,Check2
立即返回,并且由于await
语句返回控制直到等待的任务完成,因此尽管SessionStateBehavior.Required
,它也不会被阻止。为什么Check2
在Check1
返回之前没有得到值 - 第一次之后,
Check2
被卡住,直到Check1
返回,尽管Check1
是async
,为什么?重新运行应用程序后,Check1
会立即返回,如前一个问题所述,但仅返回一次 - 我的解释中有没有遗漏或说错的概念
使用ASP.NET和.NET Framework 4.5,Visual Studio 2013在Windows 7 Ultimate上运行。
对于您的问题2,如果我正确理解您正在做的是刷新两个选项卡(可能是在check2之前带有check1的选项卡),并观察到check2直到check1完成后才完成加载。
原因是asp.net处理(可能)以串行而非并行方式写入同一会话的请求。这意味着,只要有任何一个请求挂起,第二个请求甚至不会开始处理,直到第一个请求完成。使用任务、异步或手动线程处理将无法解决这种行为。原因是访问会话不是线程安全操作。潜在的解决方法是在不需要会话状态的页面中不使用会话状态,或者在不需要写入会话的页面中使用ReadOnly会话状态。
两者都是通过使用页面上的EnableSessionState
属性来实现的,或者设置为False
以禁用会话状态,或者设置成ReadOnly
以指示在对此页面的任何请求中都不写入会话。
另请参阅此处的示例答案。
对于问题1,原因可能是会话状态仅在ReleaseRequestState
生命周期事件(在请求的最后执行)之后才保持,尽管我本以为这只在使用非进程会话存储时才重要。然而,更可能的原因是,check2的请求首先执行(甚至阻止了check1的处理开始)。也许您可以详细说明如何测试它,以及如何确保哪个请求首先执行。
编辑:
可能发生的情况是:在你的第一次尝试中,你实际上并没有使用同一个会话(当你开始时,会话还没有创建,每个请求都会创建一个新的会话。这也解释了为什么在第一个请求完成之前,第二个请求不会被阻止)。然后,在第二次尝试时,两个选项卡都将使用相同的会话(因为最后写入的会话cookie由两个选项卡使用)。您可以通过打印asp会话(session.SessionID)id和/或使用无Cookie会话状态来确认这一理论