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


我有一个 Index ASP.net MVC控制器中的动作。此操作调用(除其他外)一个私有操作,该操作对具有大量行集的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();
}

这很有效。但这真的是异步吗?我想念一下,还有其他办法吗?


4887
2017-07-06 11:08


起源

请注意 SqlConnection, SqlCommand 和 SqlDataReader 全部实施 IDisposable 界面,所以你应该考虑使用 using 声明 - 这也适用于异步操作!另请参阅此问题以获取更多信息: stackoverflow.com/q/16985876/927511 - Chips_100


答案:


它的 async 打电话,但要理解的一件重要事情就是当你做控制器动作时 async 在那种情况下:处理请求返回线程池(asp.net请求线程池)的线程(asp.net线程池)。

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

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


11
2017-07-06 11:12



好的完美。但是......至少这是正确的使用async / await的方法吗? - BAD_SEED
@ marianoc84 - 是的,这是正确的方法......我的答案的第一行只告诉那件事......接受它对你有用的答案 - Pranay Rana


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

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

异步并不意味着 “将此请求返回给调用者,我将在稍后完成执行”,这有点像你期待的。它不会破坏HTTP请求 - 响应协议。你想要的是async无法实现的。

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


5
2017-07-06 11:27