在MVC控制器的动作中执行async / await

时间:2015-07-06 11:08:04

标签: c# asp.net asp.net-mvc async-await

我在ASP.net MVC控制器中有一个Index动作。此操作调用(除其他外)一个私有操作,该操作对具有大量行的SQL表进行计数。返回的号码将插入视图包属性中。

public ActionResult Index() 
{
    // do things
    ViewBag.NumberOfRows = NumberOfRows();
    return View();
}

private string NumberOfRows()
{
    // sql connection and row count
    return numberOfRows;
}

这样可行,但在执行所有之前我无法看到索引页面,甚至是行数。 相反,我会Index行动立即完成,即使私人功能尚未完成。比计数完成时,为视图包属性设置一个值。 现在我已经做到了:

private async Task<string> NumberOfRows()
{
    SqlConnection connection = new SqlConnection(connString);
    SqlCommand cmd = new SqlCommand();
    SqlDataReader reader;

    cmd.CommandText = "SELECT SUM (row_count) FROM sys.dm_db_partition_stats WHERE object_id=OBJECT_ID('aTable') AND (index_id=0 or index_id=1)";
    cmd.CommandType = CommandType.Text;
    cmd.Connection = connection;

    await connection.OpenAsync();

    reader = await cmd.ExecuteReaderAsync();
    string numberOfRows = "N/A";
    while (await reader.ReadAsync())
    {
        numberOfRows = reader.GetInt64(0).ToString();
    }

    connection.Close();

    return numberOfRows ;
}

public async Task<ActionResult> Index(FormCollection form){
    // do things;
    ViewBag.NumberOfRows = await NumberOfRows();
    return View();
}

这很有效。但这真的是异步吗?我错过了什么,还有其他方法吗?

3 个答案:

答案 0 :(得分:14)

它的async调用,但在这里要理解的一件重要事情就是在这种情况下你的控制器动作async:处理请求返回线程池的线程(asp.net线程池) asp.net请求线程池)。

这意味着它释放thead池的线程来处理更多请求(这意味着异步控制器操作只是帮助处理更多请求它并不意味着它减少了处理时间,它只是让你的服务器响应更快)。一旦在async / await下运行完成,请求线程池中的新线程就会进行进一步处理。

如果你想要真正的异步页面,即想让你的页面更具响应性,我建议使用jQuery的.ajax()函数或使用Asp.net MVC中提供的ajax extesion进行调用。

答案 1 :(得分:7)

  

这很有效。但这真的是异步吗?

一旦您查询数据库(这是一个IO绑定操作),就会异步,您可以释放ASP.NET Thread-Pool线程,而不是使用它来阻止,直到查询完成。

异步并不代表&#34;将此请求返回给来电者,我将在以后完成执行&#34; ,这有点像你&# 39;期待。它不会破坏HTTP请求 - 响应协议。你想要的不是async。

如果您希望立即完成请求,则需要在某个后台线程上对其进行排队,并在操作完成后将数据推送到客户端。

答案 2 :(得分:0)

使用Task.Run代替异步,

Task.Run(() => MethodToExecuteInBackground(methodParameters)).ConfigureAwait(false).GetAwaiter();

您还需要从控制器的Index方法中删除异步修改器。

现在,您的控制器方法将在MethodToExecuteInBackground关闭并在后台执行某些工作时立即返回。

请注意,这将占用线程池线程,直到MethodToExecuteInBackground完成为止。