如何使它异步?(async, await - C#, MVC)

本文关键字:await MVC async 何使它 异步 | 更新日期: 2023-09-27 18:34:54

我只是试图使我的 ASP .NET MVC 应用程序的一部分异步,但即使在阅读和尝试了很多之后,我也不是真正理解异步等待模式,希望有人能给我一个提示。

基本上我有以下几点:

  1. 对我的控制器的 javascript 调用,它获取图表的部分视图(在很多图表的页面加载后会发生这种情况几次(

    // Load content of one chart
    my.loadChartContent = function (data, callback) {
    $.post("/Dashboard/GetChartContent/", data, function (datain) {
        if (isFunction(callback))
            callback(datain);
    });
    };
    
  2. 调用另一个类中的数据库方法的控制器操作

    public ActionResult GetChartContent(int id, bool isDraft = false)
    {
        //do something
        //...
        var chartdata = _dataService.GetDataForChart(chart, isDraft, _user.Id); //long running query
        //do something with chartdata
        return View(chartdata);
    }
    
  3. 数据类 (_dataService(,它使用 SqlDataReader 从数据库中获取数据,并使用该数据加载数据表。

问题在于,尽管 javascript 是异步执行的,但 Controller-Actions 似乎被阻止,直到 DataService 类的结果返回。我想启动对数据库的所有查询并异步等待结果,以便长时间运行的查询不会阻止较短的查询。(在SQL Server Profiler中,我看到查询为Begin-End,Begin-End,Begin-End =>但它应该是开始 - 开始 - 开始 - 结束(

我应该在哪里使用 async-await?将其(以某种方式(用于我的控制器操作是否足够,还是有必要使整个"调用链"异步?

更新:当我使用 SQLConnection.OpenAsync 和 ExecuteReaderAsync 时,代码永远不会完成......我不明白为什么?

    public async Task<Query> GetSqlServerData(Query query)
    {
        var dt = new DataTable();
        var con = new SqlConnection(query.ConnectionString);
        await con.OpenAsync();
        var cmd = new SqlCommand(query.SelectStatement, con);
        var datareader = await cmd.ExecuteReaderAsync();
        dt.Load(datareader);
        con.Close();
        query.Result = dt;
        return query;
    }

如何使它异步?(async, await - C#, MVC)

谢谢大家的回答。但真正的答案比我想象的要简单得多。斯蒂芬用这句话为我指出了正确的方向

所有 HTTP 调用自然都是异步的。

我知道这一点,通常确实如此,但显然不是当您使用会话时 ASP.NET 因为 MVC 会等待每个请求(来自一个用户(完成以同步会话。你可以在这里找到更好的解释:http://www.stefanprodan.eu/2012/02/parallel-processing-of-concurrent-ajax-requests-in-asp-net-mvc/

所以 - 只是用

...

[SessionState(System.Web.SessionState.SessionState.SessionStateBehavior.ReadOnly(]

。做到了,现在我得到了我想要的结果 - 在我的 SQL Server 上同时查询和更快的响应时间。

@Stephen - 超过 2 个同时请求 => http://www.browserscope.org/?category=network

问题在于,尽管 javascript 是异步执行的,但 Controller-Actions 似乎被阻止,直到 DataService 类的结果返回。我想启动对数据库的所有查询并异步等待结果,以便长时间运行的查询不会阻止较短的查询。

术语"异步"可以通过几种不同的方式应用。在 JavaScript 中,一切都是异步的。所有 HTTP 调用自然都是异步的。

如果您没有看到任何 sql 重叠,那么您应该确保多次调用loadChartContent(而不是一次通过回调或类似的东西链接调用它(。浏览器将限制您同时发出两个请求,但您应该一次看到两个请求命中您的 sql 服务器。

让你的服务器端async不会帮助你,因为async不会改变HTTP协议(正如我在我的博客上描述的那样(。即使您将数据库访问设为async,您的控制器操作仍然需要等待它们完成,并且浏览器仍将限制您两个未完成的请求。服务器端async对于缩放 Web 服务器很有用,但如果 Web 服务器与单个 SQL Server 后端通信,则缩放 Web 服务器就没有意义,因为 Web 服务器不是可伸缩性的决定因素。

附带说明一下,我怀疑您的async代码永远不会完成的原因是因为您使用的是ResultWait;我在我的博客上解释了这一点。

所以,回到你最初的问题:如果你想启动对数据库的所有查询,那么你需要将API更改为"chunky"而不是"chatty"。 即,添加一个GetChartContents操作,该操作采用多个 id 并并行运行所有这些查询。我建议使用async数据库方法,如下所示:

public async Task<ActionResult> GetChartContents(int[] ids, bool isDraft = false)
{
  var charts = ...;
  var chartTasks = Enumerable.Range(0, ids.Length)
      .Select(i => _dataService.GetDataForChartAsync(charts[i], isDraft, _user.Id))
      .ToArray();
  var results = await Task.WhenAll(chartTasks);
  ...
  return View(results);
}

我认为本教程为您尝试做的事情提供了一个很好的起点。

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

如果您有:

public async Task<Query> GetSqlServerData(Query query)
{
    var dt = new DataTable();
    var con = new SqlConnection(query.ConnectionString);
    await con.OpenAsync();
    var cmd = new SqlCommand(query.SelectStatement, con);
    var datareader = await cmd.ExecuteReaderAsync();
    dt.Load(datareader);
    con.Close();
    query.Result = dt;
    return query;
}

然后使用:

query1 = await GetSqlServerData(query1);
query2 = await GetSqlServerData(query2);
query3 = await GetSqlServerData(query3);