【问题标题】:AsyncController's async action blocks requests instead of returning immediatelyAsyncController 的异步操作阻止请求而不是立即返回
【发布时间】:2013-12-05 09:29:47
【问题描述】:

这是我第一次使用 AsyncController (MVC3),我无法理解异步操作。我的任务是使用实体框架将适量的数据从 Excel 导入 SQL Server 数据库。我认为这符合异步操作的条件,因此我为此目的明确地编写了一个控制器。这是带有异步操作的控制器代码

public class CampDonorImportController : AsyncController
{
    public void CampDonorImportAsync(string fileName, int taskId) {
        ...
        HttpContext.Application["Progress" + taskId] = 0;
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(task => {
            //Code to import Excel Data
        }, taskId);
    }

    public ActionResult CampDonorImportCompleted() {
        return null;
    }

    public ActionResult ReportImportProgress(int taskId) {
        ...
        return Json(new { Progress = progress, CarryOn = carryOn, Status = status }, JsonRequestBehavior.AllowGet);

    }

我使用以下 JQuery 代码调用异步操作 (CampDonorImportAsync)

    $.ajax({
        url: importDonorUrl,
        success: function (data, textStatus, jqXHR) {
            //Repeatedly call reportImportProgress
            refreshTimerId = window.setInterval(reportImportProgress, reportTaskProgressTime);
        },
    });

reportImportProgress javascript 函数调用 ReportImportProgress() 操作,该操作显示异步操作的当前进度。

    $.ajax({
        url: reportTaskProgressUrl,
        complete: function (jqXHR, textStatus, errorThrown) {
            var json = $.parseJSON(jqXHR.responseText);
            if (!json.CarryOn) {
                endImportInit();
                alert(json.Status);
            }
        },
    });

问题在于对 Async 方法 (CampDonorImportAsync) 的调用会阻止来自同一页面的其他请求,例如上面的 ReportImportProgress()。我认为对 Async 操作的调用应该立即返回,以便可以发出其他请求,即使 Async 任务仍在进行中。我不确定为什么异步请求被阻止并等待任务完成,而不是立即返回。有什么想法吗?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 asynccontroller


    【解决方案1】:

    正如我在博客中所描述的,async does not change the HTTP protocol。使用 HTTP,每个请求都会得到一个响应,仅此而已。

    可靠的解决方案比您想象的要复杂一些。您需要一个可靠的队列(例如,Azure 队列)和一个独立的后端(例如,Azure 辅助角色)来处理来自该队列的请求。然后,您的 MVC 控制器可以将请求添加到队列并返回。然后,您的前端可以通过 SignalR 之类的方式轮询完成或收到通知。

    【讨论】:

    • 是的,我有点误解了整个异步操作。它只是返回到池中的 IIS 线程,请求仍然存在。实际上,我偶然发现了一个可行的解决方案。这是链接blog.janjonas.net/2012-01-02/…。实际上,启动新任务的 Action 方法会返回(无需等待后台任务),然后我可以定期调用我的 ReprotImportProgress 操作。它有效,但我不确定缺点(如果有的话)
    • @Nirvan:像您发布的链接那样将长时间运行的任务保存在内存中是非常危险的。我有another blog post 更详细地介绍了这一点。
    • 我已经实施了您博文中提到的解决方案。我已经对其进行了测试,并且取消令牌功能允许任务优雅地退出。通常,我们会在后台处理之前备份我们的数据库,因此您的解决方案非常适合我的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    相关资源
    最近更新 更多