MVC 5中长期运行任务的进度指示器

时间:2015-09-11 15:03:58

标签: jquery asp.net-mvc

前言:我继续使用this as the basis for what I'm doing

我正在尝试向我的用户提供一些迹象,表明提交表单实际正在做某事。

我的想法与YouTube的做法非常相似......页面顶部有一个横条,在页面的宽度上展开,以反映正在执行的任务的完成进度。

这是提交表单的jquery:

    // Task Progress Indication

    function update(taskId, status) {
        var e = $("#" + taskId);
        if (status != "Completed") {
            // increase the width of the progress indicator
            e.css("width", status);
        }
        else {
            e.hide();
        }
    }

    $("form").submit(function (e) {
        // start indicating progress
        e.preventDefault();
        $.post("Home/Start", {}, function (taskId) {

            // periodically update monitor
            var intervalId = setInterval(function () {
                $.post("Home/Progress", { id: taskId }, function (progress) {
                    if (progress >= 100) {
                        update(taskId, "Completed");
                        clearInterval(intervalId);
                    }
                    else {
                        update(taskId, progress + "%");
                    }
                });
            }, 100);
        });
        // end indicating progress

        // this is the post of the form to the Controller
        $.post($(this).attr("action"), $(this).serialize(), function (data) {
            if (!data.IsOK) { // this is some error handling that I need to fix still
                $("#modalTitle").html(data.Title);
                $("#modalMessage").html(data.Message);
                $("#modalDetail").html(data.Error).hide();
                $("#modalDialog").css("display", "block");
                $("#modalBackground").css("display", "block");
            }
            else {
                window.location.href = '@Url.Content("~/")';
            }
            return;
        });

        return false;
    });

在我的控制器上,我有以下ActionResult来处理进度指示器的更新。

private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>();

public ActionResult Start()
{
    var taskid = Guid.NewGuid();
    tasks.Add(taskid, 0);

    Task.Factory.StartNew(() =>
    {
        for (var i = 0; i <= 100; i++)
        {
            tasks[taskid] = i; // update task progress
            Thread.Sleep(50); // simulate long running operation
        }
        tasks.Remove(taskid);
    });
    return Json(taskid);
}

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

我在这里可能会出错,但我认为我在网页上看不到任何内容的原因是进度指示和表单提交之间没有任何关联。

如何通过将表单提交链接到进度指示来解决此问题?

1 个答案:

答案 0 :(得分:1)

我实现了类似的功能,在将多个ssrs pdf输出合并到一个文件中时提供反馈。在此过程中,我必须向用户提供一些反馈。这是一个痛苦,但我了解到 .NET喜欢序列化对会话的访问的方式会干扰回调的返回方式。你可能遇到了同样的问题。

John Saundersquestion指出的问题的灵魂来源就是关闭客户端进度回发的控制器方法的会话状态。

//IMPORTANT - NORMAL PROGRESS STATE SERIALIZES ACCESS TO SESSIONS - All callbacks are returned only after the controller method returns
[SessionState(SessionStateBehavior.ReadOnly)]
public class MyProgressCallbackClass
{
    ...
}