【问题标题】:async/await in MVC controller's actionMVC 控制器操作中的异步/等待
【发布时间】:2023-03-08 07:06:02
【问题描述】:

我在 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 操作。比当计数完成时为 view bag 属性设置一个值。 现在我已经这样做了:

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

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

【问题讨论】:

  • 请注意SqlConnection、SqlCommand 和SqlDataReader 都实现了IDisposable 接口,因此您应该考虑使用using 语句 - 这适用于其中的异步操作好吧!另请参阅此问题以获取更多信息:stackoverflow.com/q/16985876/927511

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


【解决方案1】:

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

这意味着它释放了广告池的线程以处理更多请求(这意味着异步控制器操作仅有助于处理更多请求,并不意味着它会减少您的处理时间,它只会使您的服务器更具响应性)。一旦 async/await 下的操作完成,请求线程池中的新线程会做进一步的处理。

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

【讨论】:

  • 好的,完美。但是……至少这是使用 async/await 的正确方法吗?
  • @marianoc84 - 是的,它的正确方式......我的答案的第一行只告诉了那个东西......接受它对你有用的答案
【解决方案2】:

这行得通。但这真的是异步的吗?

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

异步并不意味着“将此请求返回给调用者,我将在稍后完成执行”,这在某种程度上是您所期望的。它不会破坏 HTTP 请求-响应协议。你想要的不是异步实现的。

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

【讨论】:

    【解决方案3】:

    使用 Task.Run 代替异步:

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

    您还需要从控制器的 Index 方法中删除 async 修饰符。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      • 2017-10-08
      • 2012-12-07
      • 2015-10-05
      • 2012-10-14
      • 1970-01-01
      相关资源
      最近更新 更多