Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 会话状态异步时出现意外行为_C#_Asp.net_Session_Async Await_Asp.net 4.5 - Fatal编程技术网

C# 会话状态异步时出现意外行为

C# 会话状态异步时出现意外行为,c#,asp.net,session,async-await,asp.net-4.5,C#,Asp.net,Session,Async Await,Asp.net 4.5,我正在ASP.NET MVC控制器方法的上下文中调查async和await,并得到一些意外的行为 我有以下控制器类: [SessionState(System.Web.SessionState.SessionStateBehavior.Required)] public class HomeController : Controller { // GET: Home public ActionResult Index() { return View();

我正在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();
    }
}
[会话状态(System.Web.SessionState.SessionStateBehavior.Required)]
公共类HomeController:控制器
{
//到家
公共行动结果索引()
{
返回视图();
}
公共异步任务检查1()
{
会话[“测试”]=“检查”;
System.Diagnostics.Debug.WriteLine(“会话:“+会话[“测试]”);
等待任务。延迟(20000);
返回视图();
}
公共行动结果检查2()
{
var测试=会话[“测试”];
ViewBag.Test=测试;
返回视图();
}
}
以及每个方法Check1和Check2的简单视图:

检查1

@{
    ViewBag.Title = "Check1";
}

<h2>View with Delay</h2>
@{
ViewBag.Title=“检查1”;
}
延迟查看
检查2

@{
    ViewBag.Title = "Check2";
    var check = ViewBag.Test;
}

<h2>Immediate View @check</h2>
@{
ViewBag.Title=“检查2”;
var检查=ViewBag.Test;
}
即时查看@检查
现在,在启动应用程序后,当我打开
http://localhost:23131/Home/Check1
在一个选项卡和
http://localhost:23131/Home/Check2
在第二个选项卡中,对
Check1
的调用在20秒后按预期返回,对
Check2
的调用立即返回,但是它没有在会话状态下设置值,我不明白为什么。应立即设置,因为它在延迟之前。但是,输出窗口上会打印正确的值

现在,在Check1返回后,点击
Check2
选项卡上的刷新按钮将从
viewbag
中的会话中获取值并显示它

在此之后,如果我再次刷新两个选项卡,
Check2
在Check1完成后不会返回(延迟20秒),尽管Check2是
async

我的问题是:

  • 第一次打开两个选项卡时,
    Check2
    由于
    Check1
    async
    而立即返回,并且尽管
    SessionStateBehavior,它仍不会被阻止。由于
    wait
    语句在等待的任务完成之前返回控制权,因此需要执行此操作。为什么
    Check2
    Check1
    返回之前不获取值
  • 第1次之后,
    Check2
    被卡住,直到
    Check1
    返回,尽管
    Check1
    async
    ,这是为什么?重新运行应用程序后,
    Check1
    立即返回上一个问题中所述的值,但只返回一次
  • 在我的解释中是否有我遗漏或陈述错误的概念

  • 将ASP.NET与.NET Framework 4.5结合使用,Visual Studio 2013在Windows 7 Ultimate上运行。

    对于您的问题2,如果我理解正确,您要做的是刷新两个选项卡(可能是在check2之前带有check1的选项卡),并观察check2直到check1完成后才完成加载

    这是因为asp.net处理(可能)以串行方式而不是并行方式写入同一会话的请求。这意味着,只要有一个请求处于挂起状态,第二个请求甚至不会开始处理,直到第一个请求完成。使用任务、异步或手动线程处理无法解决此行为。原因是访问会话不是线程安全的操作。潜在的解决方法是在不需要会话状态的页面中不使用会话状态,或者在不需要写入会话的页面中使用只读会话状态

    这两种方法都是通过使用页面上的属性来实现的,设置为
    False
    以禁用会话状态,或设置为
    ReadOnly
    ,以指示您没有在对此页面的任何请求中写入会话

    另请参见示例答案

    对于问题1,其原因可能是会话状态仅在生命周期事件(在请求的最后执行)之后才持久化,尽管我本以为这仅在使用非会话存储时才起作用。然而,更可能的原因是,先执行对check2的请求(甚至会阻止对check1的处理的开始)。也许您可以详细说明如何准确地测试它,以及如何确保先执行哪个请求

    编辑:


    可能发生的情况是:在第一次尝试中,您实际上并没有使用相同的会话(启动时尚未创建会话,并且为每个请求创建了一个新的会话。这也解释了为什么在第一次请求完成之前不会阻止第二个请求)。然后,在第二次尝试中,两个选项卡都将使用相同的会话(因为两个选项卡都使用最后写入的会话cookie)。您可以通过打印asp会话(session.SessionID)id和/或对问题2使用无Cookie会话状态来确认这一理论,如果我理解正确,您正在做的是刷新两个选项卡(可能是在check2之前带有check1的选项卡),并观察检查2直到检查1完成后才完成加载

    这是因为asp.net处理(可能)以串行方式而不是并行方式写入同一会话的请求。这意味着,只要有一个请求处于挂起状态,第二个请求甚至不会开始处理,直到第一个请求完成。使用任务、异步或手动线程处理无法解决此行为。原因是访问会话不是线程安全的操作。潜在的解决方法是在不需要会话状态的页面中不使用会话状态,或者在不需要写入会话的页面中使用只读会话状态

    这两种方法都是通过使用页面上的属性来实现的,设置为
    False
    以禁用会话状态,或设置为
    ReadOnly
    ,以指示您没有在对此页面的任何请求中写入会话

    另见fo