MVC进度条将无法正常工作

时间:2014-07-21 03:32:50

标签: jquery asp.net-mvc progress-bar

我正在努力取得进步吧。在服务器端,我创建了一个控制器,它应该获取进度值并将值存储在会话中。

在客户端,我创建了两个ajax请求。其中一个启动一个函数,我想监视它,另一个只是检查进度阶段。我的意思是,这就是我认为它会起作用的方式。但它只会在完成后输出一些东西。

只需等待几秒钟然后发出警报即可完成!"这就是全部。

问题是什么?也许我应该在控制器中创建新线程来监控进度阶段?

这是客户端代码:

function generate() {

    setTimeout(checkProgress, 400);
        $.ajax({
            type: "POST",
            url: "/PPTReport/Generate",
            async: true,
            success: function (text) {
                 console.log(text);

            },
            error:function() {
                 console.log("error! error!");
            }
        });

  }

function checkProgress() {

    var id = "reportProgress";

    $.ajax({
        type: "POST",
        url: "/PPTReport/GetProgress",
        async: true,
        data: "id="+id,
        success: function (data) {
            if (data.done) {
                 console.log('Done!');
            } else {
                 console.log('Progress at ' + data.percent + '%');
                console.log(data.percent);
                setTimeout(checkProgress, 100 );
            }

        },
        error: function() {
            console.log('ajax error');
        }
    });
}

这是服务器端代码

public class ProgressInfo
    {
        public int Percent { get; set; }
        public bool Done { get; set; }
    }

 public JsonResult GetProgress(string id)
        {
            ProgressInfo progress;
            if (string.IsNullOrEmpty(id)
                || (progress = Session[id] as ProgressInfo) == null)
            {
                return Json(new
                {
                    success = false
                });
            }
            if (progress.Done)
            {
                Session.Remove(id);
            }
            return Json(new
                {
                    success = true,
                    done = progress.Done,
                    percent = progress.Percent
                }
            );
        }


public JsonResult Generate(){
                    //init stuff 
                    //there are somtheing like that
                    ProgressInfo progress = new ProgressInfo();
                    progress.Percent = 0;
                    progress.Done = false;
                    if (tabs > 0)
                    {
                        FirstPage();
                        progress.Percent++;
                        Session["reportProgress"] = progress;
                        if (tabs > 1)
                        {
                            SecondPage();
                            progress.Percent++;
                            Session["reportProgress"] = progress;
                            if (tabs > 2)
                            {
                                ThirdPage();
                                progress.Percent++;
                                Session["reportProgress"] = progress;
                                if (tabs > 3)
                                {
                                   LastPage();
                                }
                             }
                         }
                     }
                   //what we've gonna return stuff etc 
         }

UPD: 好吧,我终于有点做了 - 我做了测试功能(几乎就像在例子中) 这是代码:

JS:

 function doCalculation() {
            $.post('/PPTReport/DoCalculation/sas');
            setTimeout(pollProgress, 1000);
        }

        function pollProgress() {
            var progressID = "sas";
            $.post('/PPTReport/GetProgress/' + progressID, function (response) {
                if (!response.success) {
                    alert('Cannot find progress');
                    return;
                }
                if (response.done) {
                    alert('Done!');
                } else {
                    alert('Progress at ' + response.percent + '%');
                    setTimeout(pollProgress, 1000);
                }
            }, 'json');

}

服务器端:

public void DoCalculation(string id)
        {
            ProgressInfo progress = new ProgressInfo();
            if (!string.IsNullOrEmpty(id))
            {
                Session[id] = progress;
            }

            //periodicly update progress
            int i = 0;
            while(i == 0 && progress.Percent != 7600000340)
            {
                progress.Percent++;
                Thread.Sleep(1000);
            }
        }

        public JsonResult GetProgress(string id)
        {
            ProgressInfo progress;
            if (string.IsNullOrEmpty(id)
                || (progress = Session[id] as ProgressInfo) == null)
            {
                return Json(new
                {
                    success = false
                });
            }
            if (progress.Done)
            {
                Session.Remove(id);
            }
            return Json(new
            {
                success = true,
                done = progress.Done,
                percent = progress.Percent
            });
        }

但我等了一分多钟,直到行动第一次执行! Look enter image description here

为什么会这样?它只是调用简单函数,为什么要等这么久?

2 个答案:

答案 0 :(得分:7)

这是一个老问题的实例,请参见此处:

http://msdn.microsoft.com/en-us/library/ms178581.aspx

  

对于每个会话,访问ASP.NET会话状态是独占的,这意味着   如果两个不同的用户发出并发请求,则访问每个用户   同时授予单独的会话。但是,如果两个并发   请求是针对同一会话进行的(使用相同的SessionID)   value),第一个请求获得对会话的独占访问权   信息。第二个请求仅在第一个请求之后执行   完了。 (如果排他性,第二次会议也可以访问   锁定信息被释放,因为第一个请求超过了   锁定超时。)如果@Page中的EnableSessionState值   指令设置为ReadOnly,即只读会话的​​请求   信息不会导致会话数据的独占锁定。   但是,会话数据的只读请求可能仍需要等待   对于由会话数据的读写请求设置的锁定来清除。

我认为你可以找到很多关于SO的帖子来讨论这个问题。这是一个:

Asynchronous Controller is blocking requests in ASP.NET MVC through jQuery

这是一个解决方法:

Disable Session state per-request in ASP.Net MVC

好的,添加一些(未经测试的!)示例代码。这只是为了说明如何解决这个问题:

public class myCache {

    private static Dictionary<string, ProgressInfo> _pinfos = new Dictionary<string, ProgressInfo>();
    private static readonly object _lockObject = new object();

    public static void Add(string key, ProgressInfo value)
    {
        lock (_lockObject)
        {
            if (!_pinfos.ContainsKey(key)) {
                _pinfos.Add(key, value);
            }
            else {
               _pinfos[key] = value;
            }

        }
    }

    public static ProgressInfo Get(string key) {
        if (_pinfos.ContainsKey(key)) {
          return _pinfos[key];
        }
        else {
          return null;
        }
    }

    public static void Remove(string key) {         
        lock (_lockObject)
        {
          if (_pinfos.ContainsKey(key)) {
             _pinfos.Remove(key);
          }
        }
    }
}




[SessionState(SessionStateBehavior.ReadOnly)]
public class TestController : AsyncController

    public void DoCalculation(string id)
        {
            ProgressInfo progress = new ProgressInfo();
            if (!string.IsNullOrEmpty(id)) {
                myCache.Add(id,progress);
            }

            //periodicly update progress
            int i = 0;
            while(i == 0 && progress.Percent != 7600000340)
            {
                progress.Percent++;
                Thread.Sleep(1000);
            }
        }

        public JsonResult GetProgress(string id)
        {
            ProgressInfo progress;
            if (string.IsNullOrEmpty(id)
                || (progress = myCache.Get(id)) == null)
            {
                return Json(new
                {
                    success = false
                });
            }
            if (progress.Done)
            {
                myCache.Remove(id);
            }
            return Json(new
            {
                success = true,
                done = progress.Done,
                percent = progress.Percent
            });
        }
}

答案 1 :(得分:2)

Well Skarist解释了为什么它正在发生以及我遇到了什么。我做了一个(错误的)假设,即将会话状态更改为只读将阻止我写入会话,但它没有。

我为解决我的问题所做的是将EnableSessionState设置为&#34; ReadOnly&#34;在页面上我也分配了会话值。这基本上使Session不是线程安全的,并允许我在轮询服务器时拉取值。我目前正在使用WebForms,但在MVC中使用[SessionState(SessionStateBehavior.Disabled)]应该类似。