4

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

基本上我有以下几点:

  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 从数据库中获取数据并使用该数据加载 DataTable。

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

我应该在哪里使用异步等待?将它(以某种方式)用于我的控制器操作是否足够,或者是否有必要使整个“调用链”异步?

更新: 当我使用 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;
    }
4

4 回答 4

5

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

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

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

所以 - 只是用......装饰我的控制器

[会话状态(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

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

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

于 2013-10-10T13:04:17.433 回答
3

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

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

如果您没有看到任何sql 重叠,那么您应该确保您loadChartContent多次调用(而不是通过回调或类似的方式一次调用一次)。浏览器会将您限制为两个同时请求,但您应该一次看到两个请求访问您的 sql 服务器。

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

在旁注中,我怀疑您的async代码永远不会完成的原因是因为您正在使用ResultorWait ; 我在我的博客上解释了这一点。

所以,回到你原来的问题:如果你想开始对数据库的所有查询,那么你需要将 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);
}
于 2013-10-10T12:19:44.793 回答
0

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

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

于 2013-10-10T08:43:42.980 回答
0

如果你有:

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);
于 2013-10-10T11:34:57.017 回答