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

本文关键字:async await MVC 控制器 | 更新日期: 2023-09-27 18:01:15

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

public ActionResult Index() 
{
    // do things
    ViewBag.NumberOfRows = NumberOfRows();
    return View();
}
private string NumberOfRows()
{
    // sql connection and row count
    return numberOfRows;
}

这工作,但我不能看到索引页,直到一切被执行,甚至行计数。相反,我将Index动作立即完成,即使私有功能尚未完成。然后,当计数完成后,为viewbag属性设置一个值。现在我已经这样做了:

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();
}

这工作。但这真的是异步的吗?我错过什么了吗,还有别的办法吗?

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

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

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

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

这工作。但这真的是异步的吗?

它是异步的,因为一旦你查询你的数据库(这是一个IO绑定操作),你释放ASP。. NET线程池线程,而不是用它阻塞,直到查询完成。

Async并不意味着"将此请求返回给调用者,并且我将在稍后的时间完成执行",这是您所期望的。它不会破坏HTTP请求-响应协议。你想要的不是async。

如果你想让请求立即完成,你需要在后台线程中排队,并在操作完成后将数据推送到客户端。

使用Task代替async。运行:

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

你还需要从你的控制器索引方法中删除async修饰符。

现在你的控制器方法将立即返回,而MethodToExecuteInBackground关闭,并在后台做一些工作。

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