如何在MVC中耗时的操作中使用AsyncController或Task或Thread?

时间:2013-02-19 21:02:08

标签: asp.net-mvc asp.net-mvc-4 async-await

我有一个简单但耗时的操作: 当用户单击按钮时,它执行数据库密集型操作,将导入表中的记录处理到多个其他表中,一次一个导入记录。 我有一个带有触发操作的按钮的视图,在操作结束时会显示一个报告。

我正在寻找通知用户正在处理操作的方法。Here is a solution我喜欢。

我一直在网上阅读有关MVC中异步操作的内容。我发现有很多链接说如果你的进程受CPU约束,那就坚持使用同步操作了。数据库相关进程是否被视为CPU绑定?

此外,如果我得到了异步操作路由,我应该按照here所述使用AsyncController,或者只使用我在上面提到的示例中使用的任务以及here。还是他们都一样?

3 个答案:

答案 0 :(得分:3)

假设C#5.0,我会做以下事情:

// A method to get your intensive dataset
public async Task<IntensiveDataSet> GetIntensiveDataSet() {
   //in here you'll want to use any of the newer await Async calls you find 
   // available for your operations. This prevents thread blocking.

    var intensiveDataSet = new IntensiveData();
    using (var sqlCommand = new SqlCommand(SqlStatement, sqlConnection))
        {
            using (var sqlDataReader = await sqlCommand.ExecuteReaderAsync())
            {
                while (await sqlDataReader.ReadAsync())
                {
                    //build out your intensive data set.
                }
            }
        }
    return intensiveDataSet;
}


// Then in your controller, some method that uses that:
public async Task<JsonResult> Intense() {
    return Json(await GetIntensiveDataSet());
}

在你的JS中你会这样称呼它(使用JQuery):

$.get('/ControllerName/Intense').success(function(data) {
   console.log(data);
});

老实说,我只是在跑步时展示某种旋转器。

如果您确实需要向用户提供某种反馈,则必须在异步调用期间向用户的会话中添加更新...并且为了做到这一点,您需要传递对该会话的引用。然后,您只需添加另一个简单的JsonResult操作,该操作检查Session变量中的消息并在一定时间间隔内使用JQuery轮询它。虽然看起来有点矫枉过正。在大多数情况下,简单的“这可能需要一段时间”对于人们来说已经足够了。

答案 1 :(得分:2)

您需要知道的第一件事是async doesn't change the HTTP protocol。正如我在博客中描述的那样,HTTP协议为每个请求提供一个响应。因此,一旦说它处于“正在进行中”并且稍后再次返回并说它已“完成”,您将无法返回。

简单的解决方案是仅在完成后返回,并且只使用AJAX在客户端抛出一些“进行中...”通知,在请求完成时更新页面。如果你想变得更复杂,你可以使用SignalR之类的东西让服务器在请求完成时通知客户端。

特别是,async MVC动作不会“早”返回; ASP.NET将等待所有异步操作完成,然后发送响应。服务器端的async代码都是关于可伸缩性的,而不是响应性。

那就是说,我通常建议在服务器端使用异步代码。唯一的例外是,如果您只有一个数据库后端(很好地讨论了in this blog post)。如果您的后端是数据库集群或分布式/ NoSQL / SQL Azure数据库,那么您应该考虑使其异步。

如果您决定使服务器异步,只需返回Task s; AsyncController目前处于向后兼容状态。

答案 2 :(得分:0)

您应该考虑使用AJAX实现异步的选项。您可以在视图中处理客户端“...处理”消息,只需最少的麻烦,

$.ajax({
    url: @Url.Action("ActionName"),
    data: data
}).done(function(data) {
    alert('Operation Complete!');
});

alert('Operation Started');

// Display processing animation

在服务器端处理异步调用可能既昂贵,又复杂且不必要。