【问题标题】:SessionStateAttribute with behavior of Disabled seems to not working?具有 Disabled 行为的 SessionStateAttribute 似乎不起作用?
【发布时间】:2019-08-28 15:45:17
【问题描述】:

我刚刚知道会话状态阻塞,所以我正在尝试使用一个简单的 MVC 项目(创建新 MVC 项目时的默认设置)来测试禁用这种阻塞。

这是HomeController 唯一涉及的About 操作方法:

[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
    static int c = 0;
    static long ci;
    [Authorize]
    public ActionResult About()
    {
        var isSecondRequest = ++c == 2;
        //Session["a"] = 1;
        Debug.Print(">>> Started working ..." + DateTime.Now);
        if (isSecondRequest)
        {
            Debug.Print(">>> current counter: " + ci);
            for (long i = 0; i < 10000000000; i++) ;
        }            
        else
        {
            for (ci = 0; ci < 10000000000; ci++) ;
        }
        Debug.Print(">>> Finished!");
        return Content("welcome");
    }

}

我首先打开主页的两个选项卡来测试这一点。然后尝试单击第一个选项卡上的About 链接,几乎立即切换到第二个选项卡以再次单击About。所以我希望 &gt;&gt;&gt; Started working … 行应该打印 2 次,时间戳几乎相同或有大约 1 或 2 秒的微小差异,但实际差异高达 21 秒,如下所示:

>>> Started working ...4/7/2019 3:16:15 PM
>>> Started working ...4/7/2019 3:16:36 PM

所以这意味着第二个请求仍然被阻止,当我已经将属性 SessionStateAttribute 应用到 HomeController 时,这是出乎意料的。而且看起来确实在另一种意义上有效,Session 对于每个请求都是 null

你能发现这里有什么问题吗? 我的总体目的是禁用这种阻塞,以便我可以手动管理并发请求并立即向客户端返回一些有用的消息(例如第二个请求),这样它就不会显得不必要地忙碌。

【问题讨论】:

  • 原则上看起来是正确的。但是,您的 for 循环 Max 会占用您的处理器时间。请用一个简单的 Thread.Sleep(5000) 再试一次,看看会发生什么。
  • 您的目标是哪个版本的 .Net 框架?我们从我的一个问题中解决了类似的问题:stackoverflow.com/questions/42300438/…
  • @ChristophHerold 我刚刚按照您的建议尝试仅使用Thread.Sleep(5000),现在差异正好是5 秒,所以第二个仍然被阻止。
  • @MartinVenter 我的测试项目的目标是 .NET 4.5.2
  • 如果您可以升级到 4.6.2,您可以尝试通过“aspnet:AllowConcurrentRequestsPerSession”允许并发请求的会话提供程序进行科学处理?它为我们解决了很多阻塞会话的问题。 PS:您是否有任何与 global.asax 中的某些内容相关联的内容可能导致此阻塞而不是会话?

标签: c# asp.net-mvc session concurrency session-state


【解决方案1】:

根据我们的聊天记录,这是因为它位于同一个控制器上,实际上与会话没有直接关系。将其移至单独的控制器时,两个请求确实同时运行:

public class SecondaryController : Controller
{
    // GET: Secondary
    public ActionResult Index()
    {
        Debug.Print(">>> Started working ..." + DateTime.Now);
        Thread.Sleep(10000);
        Debug.Print(">>> Finished!");
        return Content("welcome");
    }
}

随着

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }


    public ActionResult About()
    {
        Debug.Print(">>> Started working ..." + DateTime.Now);
        Thread.Sleep(10000);
        Debug.Print(">>> Finished!");
        return Content("welcome");
    }

}

允许我这样做就好了,显示以下输出:

开始工作...2019 年 4 月 7 日下午 1:01:49

开始工作...2019 年 4 月 7 日下午 1:01:52

完成!

完成!

这里可能对以下内容感兴趣

“这里是交易 - IRouteHandler 有一个方法 - GetHttpHandler。当您向控制器发出 ASP.Net MVC 请求时,默认情况下,路由引擎通过创建 MvcRouteHandler 的新实例来处理请求,该实例返回一个 MvcHandler。MvcHandler是 IHttpHandler 的一个实现,它标有(惊喜!)IRequiresSessionState 接口。这就是普通请求使用 Session 的原因。”

取自Disable Session state per-request in ASP.Net MVC

【讨论】:

  • 我真的不明白在这里使用 2 个单独的控制器有什么意义。您如何将 1 个 URL(在客户端使用)映射到 2 个单独的控制器?此外,我的观点是这里应该只涉及一个控制器。从答案末尾的链接中,我还尝试创建自定义IRouteHandler,就像 Serdar 的答案一样,但它仍然无法正常工作。至少这样不使用默认的 MvcRouteHandler,所以这里不应该涉及 IRequiresSessionState。真的,我仍然相信 SessionStateAttribute 应该可以工作(正如 SamStephens 所建议的那样),但不知何故它没有。
【解决方案2】:

我真的不确定,你做错了什么。我刚刚使用 VS2017 创建了一个全新的 MVC 应用程序。我拿了 HomeController 并添加了 [SessionState(SessionStateBehavior.Disabled)] 属性。然后,我在 Index 方法中添加了以下代码:

public ActionResult Index()
{
    this.ViewBag.Start = DateTime.Now;
    System.Threading.Thread.Sleep(5000);
    this.ViewBag.End = DateTime.Now;
    return View();
}

在我看来,我补充说:

<div class="row">
    <div class="col-xs-6">Start: @this.ViewBag.Start.ToString("HH:mm:ss.fffffff")</div>
    <div class="col-xs-6">End: @this.ViewBag.End.ToString("HH:mm:ss.fffffff")</div>
</div>

现在,我启动了应用程序,打开了两个选项卡,并同时加载了它们。结果是:

Tab1: Start: 21:10:41.3620017, End: 21:10:46.3623676
Tab2: Start: 21:10:42.4819327, End: 21:10:47.4824334

因此,您可以很容易地看到,它们正在同时处理。

几年来,我的各种应用程序中都有这个用例,并且一直运行良好。 [Authorize] 也不应该考虑序列化处理,因为我在我的应用程序中这样做,而且我从来没有遇到过问题。

我还尝试使用您的代码(将 for 循环更改为 Thread.Sleep)和 Windows 身份验证。它可以正常工作。在我的其他项目中,我通常使用表单身份验证,而且我也从未遇到过问题。您使用的是什么身份验证?

【讨论】:

  • 几乎是默认的,所以我使用的身份验证类型是ApplicationCookie
  • 很奇怪,当我尝试使用 Edge 而不是 Chrome 时,它​​似乎可以工作,但实际上却不行,因为即使我不使用 SessionStateAttribute,它仍然没有被阻止,我可以调试一下,看到每个请求都有不同的SessionId(所以当然不会阻塞第二个)。现在很难理解为什么来自同一个浏览器和同一个登录用户的 2 个请求可以有不同的会话 ID?所以看起来浏览器也可能导致原始问题:(
  • 其实这点很好。 AFAIK,只要您没有向会话写入任何内容,ASP.NET 就足够智能,不会实际启动会话,因此您将没有可用的会话 cookie。因此,不会有阻塞。我将再次检查初始化会话并让您知道我的结果。
  • 问题是 2 个浏览器对同一个代码的行为不同
  • 也许,一个浏览器仍然有一个早期开发的会话 cookie。那一个将被保留。另一个很干净,因此每次通话都会获得一个新会话。尝试从您的 Chrome 浏览器中清除所有 cookie 和应用程序数据。然后它也应该总是得到一个新的会话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 2018-02-04
  • 2016-11-29
  • 2016-02-01
  • 2020-09-23
  • 2010-12-05
相关资源
最近更新 更多