代码之家  ›  专栏  ›  技术社区  ›  Christopher

如果会话正在使用,单个ASP.NET用户能否一次发出多个请求?

  •  15
  • Christopher  · 技术社区  · 16 年前

    会话处于活动状态时,我无法在ASP.NET中一次发出多个请求。为什么存在这种限制?有办法解决这个问题吗?

    这个问题可以用一个只有3个简单的ASPX页面的WebForms应用程序来演示(尽管这个限制仍然适用于ASP.NET MVC)。

    创建ASP.NET 3.5 Web应用程序。

    应该只有三页: nowait.aspx、wait.aspx和sessionstart.aspx

    nowait.aspx在默认的DIV标记之间添加了这个小金块:<%=datetime.now.ticks%>。此页的代码隐藏为默认值(空)。

    wait.aspx看起来就像nowait.aspx,但是它在后面的代码中有一行添加到页面加载:thread.sleep(3000);//等待3秒

    sessionstart.aspx看起来也像nowait.aspx,但它的代码中有这一行:session[“whatever”]=“anything”;

    打开浏览器并转到nowait.aspx。它正确地在响应中显示一个数字,例如:“633937963004391610”。不断刷新并不断更改号码。伟大的到目前为止!在同一浏览器中创建一个新选项卡,并转到wait.aspx。它保持3秒钟,然后将数字写入响应。伟大的到目前为止!不,试试这个:转到wait.aspx,当它旋转时,快速切换到no wait.aspx并刷新。即使wait.aspx正在休眠,nowait.aspx也将提供响应。迄今为止很棒。当wait.aspx旋转时,您可以继续刷新nowait.aspx,并且服务器每次都愉快地发送响应。这是我所期望的行为。

    现在是它变得奇怪的地方。

    在第三个选项卡中,在同一浏览器中,访问sessionstart.aspx。接下来,切换到wait.aspx并刷新。当它旋转时,切换到nowait.aspx并刷新。在wait.aspx运行完成之前,nowait.aspx不会发送响应!

    这证明了当会话处于活动状态时,不能与同一个用户进行并发请求。所有请求都排队并同步服务。我不期望也不理解这种行为。我已经在Visual Studio 2008的内置Web服务器,以及IIs7和IIs7.5上对此进行了测试。

    所以我有几个问题:

    1)我是否正确地认为这里确实存在限制,或者我的上述测试因我做错了什么而无效?

    2)是否有解决这一限制的方法?在我的Web应用程序中,某些操作需要很长时间才能执行,我希望用户能够在其他选项卡中执行操作,同时等待一个大的请求完成。我能以某种方式将会话配置为允许“脏读”吗?这可以防止它在请求期间被锁定?

    3)为什么存在这种限制?我想很好地理解为什么这种限制是必要的。如果我知道的话,我想我会是一个更好的开发者!

    2 回复  |  直到 16 年前
        1
  •  11
  •   kemiller2002    16 年前

    Here is a link talking about session state and locking. 它确实执行和独占锁定。

    解决这个问题的最简单方法是使长时间运行的任务异步进行。您可以使长时间运行的任务在单独的线程上运行,或者使用和 asynchronous delegate 并立即返回对浏览器的响应。客户端页面可以向服务器发送请求,以检查是否完成(最有可能是通过Ajax),当服务器通知客户端完成后,通知用户。这样一来,尽管服务器必须一次处理一个服务器请求,但对用户来说并不是这样。

    这确实有它自己的一组问题,您必须确保关闭HTTP上下文的帐户,因为它将在ASP.NET会话中释放某些功能。您可能需要考虑的一个例子是,如果会话确实发生了锁的释放,那么就可能发生这种情况。

    这并不奇怪,因为这可能是一个限制。每个浏览器都有自己的会话,在Ajax出现之前,回发请求是同步的。使同一个会话句柄并发可能会变得非常难看,而且我可以看到,这对于IIS和ASP.NET团队来说是多么的不重要。

        2
  •  9
  •   Jeff Sternal    16 年前

    由于Kevin所描述的原因,用户无法访问可能同时写入会话状态的两个页面——框架本身无法对会话存储的锁定实施细粒度控制,因此必须对整个请求进行锁定。

    为了解决这个问题,只有 阅读 会话数据可以声明它们是这样做的。ASP.NET无法获取会话状态写锁定:

    // Or false if it doesn't need access to session state at all
    EnableSessionState="ReadOnly"