MVC进度条不能正常工作

时间:2023-01-17 14:20:37

I am trying to make progress bar. On the server side I created a controller, which should get the progress value and store the value in session.

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

On the client side I created two ajax requests. One of them starts a function, which I want to be monitoring, and the other one just checks the progress stage. I mean, that's how I thought it would work. But it only outputs something when it's done.

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

It just waits for few seconds and then alerts "Done!" and that's all.

它只需要等待几秒钟,然后就会发出“完成”的警报,仅此而已。

What's the problem? Maybe I should to create new thread in the controller to monitoring the progress stage?

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

Here's the client side code:

以下是客户端代码:

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');
        }
    });
}

Here's the server side code

这是服务器端代码

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: well, I finally kinda make it - I made test function (almost like in example) Here's the code:

UPD:好吧,我终于做到了——我做了测试函数(就像在例子中一样)。

js:

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');

}

}

server-side:

服务器端:

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
            });
        }

but I wait more than a minute until the action will execute for the first time! Look MVC进度条不能正常工作

但我等了不止一分钟,直到动作第一次执行!看

Why does it happen? It just calling simple function, why does it wait so long?

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

2 个解决方案

#1


7  

This is an instance of an old problem, see here:

这是一个老问题的例子,请看这里:

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

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

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out.) If the EnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.

使用ASP。NET会话状态是每个会话的独占状态,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权。但是,如果对同一会话发出两个并发请求(通过使用相同的SessionID值),第一个请求将获得对会话信息的独占访问。第二个请求仅在第一个请求完成之后才执行。(如果释放了信息上的独占锁,则第二个会话也可以获得访问权,因为第一个请求超过了锁超时。)如果@ Page指令中的EnableSessionState值设置为只读,则对只读会话信息的请求不会导致会话数据的独占锁定。但是,对会话数据的只读请求可能仍然需要等待会话数据的读写请求设置的锁。

I think you can find numerous posts on SO that discuss this. Here is one:

我认为你可以找到很多讨论这个的文章。这里有一个:

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

异步控制器在ASP中阻塞请求。净MVC通过jQuery

and here is one workaround:

这里有一个解决办法:

Disable Session state per-request in ASP.Net MVC

在ASP中禁用每个请求的会话状态。Net MVC

Ok adding some (untested!) example code. This is just to indicate how to solve this:

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

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
            });
        }
}

#2


2  

Well Skarist explained WHY it's happening and what I was running into as well. I made an (incorrect) assumption that changing the Session State to read only would prevent me from writing to the Session, but it doesn't.

Skarist解释了为什么会发生,以及我遇到的。我做了一个(错误的)假设,将会话状态更改为read只会阻止我向会话写入,但事实并非如此。

What I did to solve my problem is set the EnableSessionState to "ReadOnly" on the page I was assigning the session values in as well. This basically makes the Session not thread safe and allowed me to pull the values when I polled the server. I'm using WebForms for this at the moment, but it should be similar in MVC using [SessionState(SessionStateBehavior.Disabled)].

我解决问题的方法是将EnableSessionState设置为“ReadOnly”,在我正在分配会话值的页面上也是如此。这基本上使会话不安全,并允许我在轮询服务器时提取值。我现在正在使用WebForms,但是在MVC中应该使用[SessionState(sessionstateaction . disabled)]。

#1


7  

This is an instance of an old problem, see here:

这是一个老问题的例子,请看这里:

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

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

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out.) If the EnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.

使用ASP。NET会话状态是每个会话的独占状态,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权。但是,如果对同一会话发出两个并发请求(通过使用相同的SessionID值),第一个请求将获得对会话信息的独占访问。第二个请求仅在第一个请求完成之后才执行。(如果释放了信息上的独占锁,则第二个会话也可以获得访问权,因为第一个请求超过了锁超时。)如果@ Page指令中的EnableSessionState值设置为只读,则对只读会话信息的请求不会导致会话数据的独占锁定。但是,对会话数据的只读请求可能仍然需要等待会话数据的读写请求设置的锁。

I think you can find numerous posts on SO that discuss this. Here is one:

我认为你可以找到很多讨论这个的文章。这里有一个:

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

异步控制器在ASP中阻塞请求。净MVC通过jQuery

and here is one workaround:

这里有一个解决办法:

Disable Session state per-request in ASP.Net MVC

在ASP中禁用每个请求的会话状态。Net MVC

Ok adding some (untested!) example code. This is just to indicate how to solve this:

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

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
            });
        }
}

#2


2  

Well Skarist explained WHY it's happening and what I was running into as well. I made an (incorrect) assumption that changing the Session State to read only would prevent me from writing to the Session, but it doesn't.

Skarist解释了为什么会发生,以及我遇到的。我做了一个(错误的)假设,将会话状态更改为read只会阻止我向会话写入,但事实并非如此。

What I did to solve my problem is set the EnableSessionState to "ReadOnly" on the page I was assigning the session values in as well. This basically makes the Session not thread safe and allowed me to pull the values when I polled the server. I'm using WebForms for this at the moment, but it should be similar in MVC using [SessionState(SessionStateBehavior.Disabled)].

我解决问题的方法是将EnableSessionState设置为“ReadOnly”,在我正在分配会话值的页面上也是如此。这基本上使会话不安全,并允许我在轮询服务器时提取值。我现在正在使用WebForms,但是在MVC中应该使用[SessionState(sessionstateaction . disabled)]。