asp.net MVC Session锁的问题

前言

解决方案:VS2017创建的Web项目。

说明:尝试理解Session锁的运行机制以及对应的处理操作。

知识点:

1.在后台中进行了Session操作,会在请求结束时生成一个新的SessionId返回给浏览器,并以cookie的形式保存起来。

2.Session锁是针对同一个SessionId,才会发生堵塞。

3.目前使用Controller添加Session.ReadOnly特性的方法,处理

4.如果考虑ajax的性能,需要考虑后台操作Session时导致堵塞的问题。

过程

问题重现

1.页面代码

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>测试Session锁</h2>
<script src="~/Scripts/jquery-3.3.1.js"></script>
<script type="text/javascript">
    $(function () {
        $('#btn1').on('click', function () {
            urlAjax("/Pro/Test1", 3);
        });
        $('#btn2').on('click', function () {
            urlAjax("/Pro/Test2", 3);
        });
    });
</script>
<div id="div1" style="width:100%; height:200px; border:1px solid #000;">
</div>
<button id="btn1">不操作Session</button>
<button id="btn2">操作Session</button>
<script>
    function urlAjax(url, count) {
        for (var i = 0; i < count; i++) {
            $.ajax({
                url: url,
                dataType: "text",
                async: true,
                success: function (response) {
                    $("#div1").html($("#div1").html() + response + "<br/>");
                }
            });
        }
    }
</script>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;

namespace webSession.Controllers
{
    public class ProController : Controller
    {
        // GET: Pro
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Test1()
        {
            Thread.Sleep(2000);
            return Content($"任务Test1完成,{DateTime.Now.ToString("yyyyMMddHHmmssfff")}");
        }

        public ActionResult Test2()
        {
            Thread.Sleep(2000);
            Session["mysession"] = "admin";
            return Content($"任务Test1完成,{DateTime.Now.ToString("yyyyMMddHHmmssfff")}");
        }
    }
}

2.准备:将浏览器保存的SessionId全部删除

 

 

 3.运行结果

(1)点击“不操作Session”按钮

结果:

提交三次请求,三个请求同时进行。

说明:

ajax设置异步请求

此时没有SessionId,且没有进行Session操作,所以没有触发Session锁,请求会同时进行。

 

 (2)点击“操作Session”按钮

结果:

提交三次请求,三个请求同时进行。

说明:

ajax设置异步请求

第一次请求是没有SessionId的,但是后台有Session操作,为什么没有触发Session锁呢?

因为SessionId是后台进行了Session操作后,在请求结束后,生成一个新的SessionId返回给浏览器,

而这三个请求是异步进行,在第二个第三个请求发起时,第一个请求并未结束,也就没有获取到,

这三个请求也是会生成三个SessionId。

 

 

 

 可以看到这三个请求返回的SessionId不一样,也佐证了上面的描述。

 

 此时,浏览器保存了最后一次请求返回的SessionId,之后再发起请求时就会发生Session锁堵塞的问题了。

 (3)再次点击“不操作Session”按钮

 

结果:

提交三次请求,三个请求发生了堵塞。

说明:

浏览器有保存SessionId,发生了Session堵塞,下一个请求需要等待前一个请求结束才会响应。

(4)奇怪的事情

手贱,编译了下解决方案。然后把运行的页面F5刷新了下。

此时是有SessionId的了,按我的理解此时,无论我调用的接口是否操作Session应该都会堵塞,

但是实际上,我第一次发点击后,2个按钮请求的三个响应,都是同时进行,第二次点击才会被堵塞。

What The Hell ???我这个小朋友,现在有很多问号

 

解决办法

1.在web.config文件中关闭session

<system.web>
  <sessionState mode="Off" />
</system.web>

 

 结果:

点击事件:点击“btn1”,点击“btn2”,点击“btn1”,点击“btn2”

未操作Session的接口正常执行,

操作Session的接口提示500,因为禁用了Session,后台抛异常了。

说明:

此解决方案就不能操作Session了,如果进行了Session操作,代码编译不会提示错误,运行时会抛出异常。

2.Controller添加[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]特性

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

 结果:

点击事件:点击“btn1”,点击“btn2”,点击“btn1”,点击“btn2”

都正常执行,且没有被堵塞,操作Session的代码也没有抛异常。

说明:

该Controller无法操作Session,只能读取。

3.改用Customer模式,自己实现会话状态存储提供程序

<sessionState mode="Custom" customProvider="CustomSessionProvider" >
  <providers>
    <add name="CustomSessionProvider" type="sessionTest.Extensions.CustomSessionProvider" />
  </providers>
</sessionState>

此方法未做实现,详情参见

https://blog.csdn.net/chunqiao_p/article/details/77877951

posted @ 2020-04-28 11:33  我有我奥妙  阅读(394)  评论(0编辑  收藏  举报