MVC 6 异步操作

MVC 6 asynchronous action

所以我开始了将我的 nHibernate 网站转换为使用 Dapper 的概念验证。

我正在使用的操作方法现在似乎有效:

public IActionResult About()
{
    ViewData["Message"] = "Your application description page.";

    var invoice = invoiceRepo.GetInvoiceAsync(19992031);
    var allInvoices = invoiceRepo.GetAllInvoicesAsync();

    var model = new Models.AboutModel
    {
        Invoice = invoice.Result,
        AllInvoices = allInvoices.Result
    };

    return View(model);
}

但后来我 realized/remembered,为了让它是异步的,我需要 Task 在动作上,像这样:

public Task<IActionResult> About()
{
    ViewData["Message"] = "Your application description page.";

    var invoice = invoiceRepo.GetInvoiceAsync(19992031);
    var allInvoices = invoiceRepo.GetAllInvoicesAsync();

    var model = new Models.AboutModel
    {
        Invoice = invoice.Result,
        AllInvoices = allInvoices.Result
    };

    return View(model);
}

但是我一这样做,它就告诉我需要等待一些事情。在我见过的所有示例中,它只是显示如下内容:

var result = await repo.Get(param);

但我已经在我的存储库中执行 "awaiting"。

public async Task<Invoice> GetInvoiceAsync(int invoiceId)
{
    const string query = "select InvoiceId, Name [InvoiceName] from dbo.Invoice where InvoiceId = @invoiceId";

    using (var conn = GetConnection())
    {
        var dp = new DynamicParameters();
        dp.Add("@invoiceId", invoiceId);

        await conn.OpenAsync();
        var invoiceResult = await conn.QueryAsync<Invoice>(query, dp, null, 30, CommandType.Text);
        var invoice = invoiceResult.SingleOrDefault();

        return invoice;
    }
}

public async Task<List<Invoice>> GetAllInvoicesAsync()
{
    const string query = "select InvoiceId, Name [InvoiceName] from dbo.Invoice where SalesPeriodId >= 17";

    using (var conn = GetConnection())
    {
        await conn.OpenAsync();
        var invoiceResult = await conn.QueryAsync<Invoice>(query, null, null, 30, CommandType.Text);
        var invoices = invoiceResult.Take(1000).ToList();

        return invoices;
    }
}

所以我切换到异步的全部意义在于能够异步执行我的两个调用,然后在返回时将结果合并在一起。

如何更改我的控制器操作以异步执行此操作,同时具有 Task<IActionResult>?像这样:

public Task<IActionResult>About() {}

更新:这是正确的吗?

public async Task<IActionResult> About()
{
    ViewData["Message"] = "Your application description page.";

    var invoice = invoiceRepo.GetInvoiceAsync(19992031);
    var allInvoices = invoiceRepo.GetAllInvoicesAsync();

    var model = new Models.AboutModel
    {
        Invoice = await invoice,
        AllInvoices = await allInvoices
    };

    return View(model);
}

这会异步(并行)执行两个 repo 调用吗?

您也需要在控制器中等待。经验法则:永远不要说 .Result,而是说 await.

您还应该将您的操作方法也声明为 public async

更新:这将是异步调用存储库的正确方法。数据库调用应该并行发生,因为两个任务都在等待任何事情之前开始。您总是可以通过将调试日志记录放在数据库方法的开头和结尾来自己看到这一点,如果您的查询相当慢,您会看到得到 "start 1 start 2 end 1 end 2" 或类似的东西而不是 "start 1 end 1 start 2 end 2"。