zoukankan      html  css  js  c++  java
  • ASP.NET MVC之Session State性能问题(七)

    前言

    这一节翻译一篇有关Session State性能问题的文章,非一字一句翻译。

    话题

    不知道我们在真实环境中是否用到了Session State特性,它主要用来当在同一浏览器发出多个请求时来存储数据,在现在我们更多的为了避免整个页面刷新,Web应用程序更多倾向于利用高扩展性的Ajax,但是不知道我们是否注意到当我们使用Session数据多次请求MVC上的Action方法时产生的性能问题呢?

    将Session放入上下文中(Put Session into the Context)

    在进行代码演示时我们首先得知道Session的工作原理:当一个新请求第一次到达服务器时,显然在此之前Cookie中没有SessionId的,此时服务器将创建一个新的Session标识,通过如下:

    System.Web.HttpContext.Current.Session.SessionID

    但是并不意味着当有多个请求发送到服务器上时,服务器都会保存一个Session Cookie。只是在Session中保存具体请求的数据,换言之,ASP.NET Framework会首先会添加Session Cookie到响应流中,此时需要保存的数据将被保存在Session中。

    因此,说到这里好像和我们要讲的主题半毛钱关系都没有,那跟我们的性能有什么关系呢?ASP.NET能够处理来自同一浏览器的多个请求,如下:

    在上述图片中,当浏览器未发出请求时显然在服务器上不会存储任何Session数据,如果服务器存储了一些数据在Session中,此时将会添加一个Session Cookie到响应流中,接下来所有的子请求使用相同的Session Cookie,同时会以队列的形式依次等待被处理。

    我们能够想象到一种很常见的场景,要是多个请求同时去读取或修改相同的Session值,此时则会造成不一致的数据。接下来进入我们话题演示时间。

    代码演示

    我们在控制器中给出如下代码:

        [OutputCache(NoStore = true, Duration = 0)] //不缓存数据
        public class HomeController : Controller
        {
            public List<string> boxes = new List<string>() { "red", "green", "blue", "black", "gray", "yellow", "orange" };
            // GET: Home
            public ActionResult Index()
            {
                return View();
            }
    
            public string GetBox() //随机获取集合中颜色
            {
                System.Threading.Thread.Sleep(10);
                Random rnd = new Random();
                int index = rnd.Next(0, boxes.Count);
    
                return boxes[index]; 
            }
    
            public ActionResult StartSession() //启动Session并存值
            {
                System.Web.HttpContext.Current.Session["Name"] = "Chris";
    
                return RedirectToAction("Index");
            }
        }

    接下来我们利用AngularJS在视图中发出Ajax请求以及其他操作,我们看看视图中代码:

    <body ng-controller="asyncCtrl" ng-init="getBoxes()">
        <nav role="navigation" class="navbar navbar-default navbar-fixed-top">
            <div class="container-fluid">
                <!-- Brand and toggle get grouped for better mobile display -->
                <div class="navbar-header">
                    <button type="button" data-target="#navbarCollapse" data-toggle="collapse" class="navbar-toggle">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                </div>
                <!-- Collection of nav links and other content for toggling -->
                <div id="navbarCollapse" class="collapse navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li class="active"><a href="#">Performace testing</a></li>
                        <li>
                            @Html.ActionLink("Start Session", "StartSession")
                        </li>
                        <li>
                            <a class="links" ng-click="getBoxes()">Not resolved</a>
                        </li>
                        <li>
                            <a class="links" ng-click="getBoxes(true)">Resolved</a>
                        </li>
                        <li>
                            <form class="navbar-form">
                                <label class="checkbox" style="margin-top:5px">
                                    @Html.CheckBox("isSessionNewChk", Session.IsNewSession, new { @disabled = "disabled" })
                                    Is Session new
                                </label>
                            </form>
                        </li>
                    </ul>
                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="#">{{boxes.length}} Boxes</a></li>
                    </ul>
                </div>
            </div>
        </nav>
        <br /><br /><br />
        <div class="container">
            <div class="row">
                <div id="boxesContainer" ng-repeat="color in boxes track by $index">
                    <div class="box" ng-class="color" />
                </div>
            </div>
            <br />
            <div class="row">
                <div id="timeOccured" ng-show="showResults" class="alert" ng-class="isResolved()" ng-bind="timeElapsed"></div>
            </div>
        </div>
        <script src="~/Scripts/app.js"></script>
    </body>

    接下来我们看看 app.js 

    angular.module('asyncApp', [])
        .value('mvcuri', 'http://localhost:49588/home/getbox')
        .value('mvcurisessionresolved', 'http://localhost:49588/SessionResolved/getbox')
        .controller('asyncCtrl', function ($http, $scope, mvcuri, mvcurisessionresolved) {
    
            $scope.boxes = [];
            $scope.showResults = false;
            var uri;
    
            $scope.getBoxes = function (resolved) {
                var start = new Date();
                var counter = 300;
    
                
                if (resolved)
                    uri = mvcurisessionresolved;
                else
                    uri = mvcuri;
    
                // Init variables
                $scope.boxes = [];
                $scope.showResults = false;
                $scope.timeElapsed = '';
    
                for (var i = 0; i < 300; i++) {
                    $http.get(uri)
                        .success(function (data, status, headers, config) {
                            $scope.boxes.push(data);
                            counter--;
    
                            if (counter == 0) {
                                var time = new Date().getTime() - start.getTime();
                                $scope.timeElapsed = 'Time elapsed (ms): ' + time;
                                $scope.showResults = true;
                            }
                        })
                            .error(function (error) {
                                $scope.timeElapsed = error.Message;
                            }).finally(function () {
                            });
                }
            };
    
            $scope.isResolved = function () {
                return uri == mvcuri ? 'alert-danger' : 'alert-success';
            }
    
        });

    上述AngularJS脚本比较简单就不叙述。接下来再创建一个控制器 SessionResolvedController 来进行比较。

        [OutputCache(NoStore = true, Duration = 0)]
        public class SessionResolvedController : Controller
        {
            public List<string> boxes = new List<string>() { "red", "green", "blue", "black", "gray", "yellow", "orange" };
    
            public string GetBox()
            {
                try
                {
                    System.Threading.Thread.Sleep(10);
                    Random rnd = new Random();
                    int index = rnd.Next(0, boxes.Count);
    
                    return boxes[index];
                }
                catch(Exception ex)
                {
                    return "red";
                }
            }
        }

    此时我们看看运行效果:

    当我们运行程序时,此时复选框是勾上的,说明此时还未有添加数据到Session中,接下来我们点击 Start Session 看看效果:

    上述我们是启动Start Session并控制整发出300个Ajax请求并返回随机颜色。我们看到花了8722毫秒。 

    接下来我们点击 Not resolved 看看耗时多少,如下:

    耗时8166毫秒,看来和启动Session没什么区别可言。因为每个到服务器的请求都有一个Session Cookie,此时所有的请求将会被依次处理正如我们之前所描述的那样,所以接下来我们进行如下操作:

        [SessionState(SessionStateBehavior.Disabled)]
        public class SessionResolvedController : Controller
        {.....}

    我们禁用SessionState看看效果:

    注意:上述程序运行建议在Release模式下进行演示,可能这样的效果更加明显。

    参考

    ASP.NET MVC Session state Performance Issue

    结语

    当有多个请求发送到服务器时此时若进行Session操作将会对性能产生一定影响。我们通过设置  [SessionState(SessionStateBehavior.Disabled)] 特性最终验证了这一观点。但是这样设置后我们将无法获取Session中的值。所以在请求数量较多的情况下,建议对于Ajax请求使用Web APi来完成,我们通过Web APi来接收Ajax请求,可以使用Session中的数据来渲染视图或者提交到数据或者参数到MVC控制器的Action方法上。

  • 相关阅读:
    dll反编译工具(ILSpy)的使用
    织梦CMS进入自定义表单界面查看数据
    SQL -注释方法
    SQL之CASE WHEN用法详解
    Windows Installer Clean Up 软件卸载工具下载
    【精华合辑】金蝶云BOS资料合辑
    报表二次开发添加自定义字段的指导方案
    怎样选购笔记本内存条?
    SQL Server 2008修改sa密码的详细方法
    VS 2015 2019注册码
  • 原文地址:https://www.cnblogs.com/CreateMyself/p/5408400.html
Copyright © 2011-2022 走看看