0

因此,我试图在一个非常慢且长的查询中添加一个异步进度条,该查询将一堆行插入数据库。我的实现基于这个例子:http ://blog.janjonas.net/2012-01-02/asp_net-mvc_3-async-jquery-progress-indicator-long-running-tasks

这是进度条的javascript代码

function updateMonitor(taskId, status) {
        $("#monitors").html("Task [" + taskId + "]: " + status);
    }
//other code
if (doSend == true) {
            $.post("/SendBatch/HandleBatchRequest", {
                //other code
            },
            function (taskId) {

                // Init monitors
                //breakpoint here only stops it once the "/SendBatch/HandleBatchRequest" is done. PROBLEM.
                $("#monitors").append($("<p id='" + taskId + "'/>"));
                updateMonitor(taskId, "Started");

                // Periodically update monitors
                var intervalId = setInterval(function () {
                    $.post("SendBatch/Progress", { id: taskId }, function (progress) {
                    if (progress >= 100) {
                        updateMonitor(taskId, "Completed");
                        clearInterval(intervalId);
                    } else {
                        updateMonitor(taskId, progress + "%");
                    }
                });
            }, 100);
        }       
        ,"html");

然后是网站显示部分的DIV

<div id="monitors"></div>

这是控制器的外观

public SendBatchController
    //some code
private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>();

public ActionResult HandleBatchRequest(
        //some code
    )
    {
        var taskId = Guid.NewGuid();
        tasks.Add(taskId, 0);



        var batchId = Guid.NewGuid().ToString("N");
        var costd = cost.ToDecimal();

        IEnumerable<BatchListModel> customers;

        try
        {
            customers = new CustomerService(_customerRepository.Session).GetCustomers(
                //some code
                );
        }
        catch (Exception err)
        {
            return Json(err.Message);
        }
        if (doSend)
        {
            var sent = 0;

            foreach (var c in customers)
            {
                try
                {
                    var usr = _customerRepository.LoadByID(c.ID);

                    var message = new ComLog
                                      {
                                          //insertions to log
                                      };

                    _comLogRepository.Save(message);
                    sent++;

                    //progress bar part inside here that is important comes here:
                    tasks[taskId] = sent;

                }
                catch (Exception e)
                {
                    Log.WriteLine("ERR:" + e);
                }

                tasks.Remove(taskId);

            }
            return Json(taskId);

        }

        return Json(customers.Count() + " customers");
    }

    public ActionResult Progress(Guid id)
    {
        return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
    }

这不起作用。该过程在后台运行。查询完成后,DIV 会显示“完成”消息。它在查询期间不显示。我不确定异步的东西是如何工作的,所以这里可能存在一些逻辑错误。例如,它甚至知道总共有多少客户吗?代码的另一个关键部分是“tasks[taskId] = sent;” 我不确定是否正确完成。

4

3 回答 3

1

HandleBatchRequest在 javascript 方面,开始进度检查的函数在请求成功完成后才会触发。第三个参数$.post()是请求成功后触发的内容。

您要么需要让您的 C# 控制器立即返回任务 ID,然后将数据库插入传送到另一个线程/后台工作程序中(更多内容请参见下文)。或者让 Javascript 随机生成 taskId 并传递给 C# 控制器。

从那里开始,正如 Brad 所提到的,您不想在其中使用 ajax 请求执行 setInterval。由于 AJAX 是异步的,因此您可能需要等待一段时间才能让服务器返回响应。为了防止同时发生多个请求并在后端服务器上造成撤消压力,您需要执行以下操作:

var taskId = 0;
$.post('/SendBatch/HandleBatchRequest', {}, function(r) {
    taskId = r;  // set task id from 
    $("#monitors").append($("<p id='" + taskId + "'/>"));
    CheckProgress();
}, 'html');

function CheckProgress() {
    $.post("SendBatch/Progress", { id: taskId }, function (progress) {
    if (progress >= 100) {
        updateMonitor(taskId, "Completed");
    } else {
        updateMonitor(taskId, progress + "%");
        setTimeout(function() {
            CheckProgress()
        }, 1000);
    }
}

在 C# 方面,控制器在每个 web 请求上都会被实例化,所以当你去检查进度时,控制器是tasks空的。您需要将实际记录卸载到某种后台工作程序/线程中,该工作程序/线程执行从控制器插入记录的实际工作。如果您经常这样做,您可能希望查看安装在服务器本身上的某种后台服务,该服务会持续运行以优化事物并为您提供最佳的灵活性。

于 2013-02-21T21:56:11.443 回答
0

为什么不向您的网站添加加载 gif(您可以在此处下载它们 - http://www.ajaxload.info/)然后将此加载 gif 放置在页面上的 div 中 - 无论您希望它显示在哪里。

类似下面的东西

<div><img class="hidden " id="LoadingGif" src='../Content/Styles/images/loading.gif' height="100" /></div>

然后在您的 js 文件中,simplay 删除 LoadingGif id 上隐藏的类,并可能将隐藏的类添加到您的监视器 div。

隐藏类应如下所示在您的 site.css

.hidden  {visibility:hidden; display:none;}
于 2013-02-24T19:58:28.743 回答
0

我强烈建议不要在 setInterval 函数中使用 ajax。相反,在 $.post() 的成功/完成回调函数中使用 setTimeout。这将保证请求是按顺序生成的。

如果您每 100 毫秒触发一次 ajax 请求,它们将很快失去同步,无疑会导致问题。

于 2013-02-21T21:27:16.993 回答