异步方法中的警告消息表示缺少await运算符

34

我在我的asp.net mvc 4应用程序中有一个Excel下载功能。 当我单击导出按钮时,会调用下面的控制器方法。 由于我需要它异步完成,因此我在这里使用了async和await。

public async Task<ActionResult> GenerateReportExcel()
    {
        ExcelGenerator excel = new ExcelGenerator();
        var filePath = await excel.ReportExcelAsync(midyearReportViewModel);
        System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
        response.ClearContent();
        response.Clear();
        response.ContentType = "text/plain";
        response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.xlsx;", PdaResource.ReportFileName)); 
        response.TransmitFile(filePath);
        response.Flush();
        response.End();
        return PartialView("_MidYearReportPartial", midyearReportViewModel);
    }

这种方法会调用一个Excel生成器方法 ReportExcelAsync,如下所示

public async Task<string> ReportExcelAsync(MidYearReportViewModel _midyearAnnualviewModel)
    {
        string fileName = "MidYearReport";
        string finalXcelPath = string.Empty;
        string currentDirectorypath = new DirectoryInfo(HttpContext.Current.Server.MapPath("~/Export")).ToString();
        finalXcelPath = string.Format("{0}\\{1}.xlsx", currentDirectorypath, fileName);
        if (System.IO.File.Exists(finalXcelPath))
        {
            System.IO.File.Delete(finalXcelPath);
        }
        var newFile = new FileInfo(finalXcelPath);
        using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
        {
            using (var package = new ExcelPackage(newFile))
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(resxSet.GetString("ReportMYMidYearExcelSheetName"));
                for (int i = 1; i <= header.Count(); i++)
                {
                    worksheet.Cells[1, i].Value = header[i - 1];
                    worksheet.Cells[1, i].Style.Font.Bold = true;
                    worksheet.Cells[1, i].Style.Fill.PatternType = ExcelFillStyle.Solid;
                    worksheet.Cells[1, i].Style.Font.Color.SetColor(Color.White);
                    worksheet.Cells[1, i].Style.Fill.BackgroundColor.SetColor(Color.DimGray);
                }
                package.Save();
            }
        }
        return finalXcelPath; 
    }

但我收到了一个警告消息,警告内容如下:

此异步方法缺少 'await' 操作符并将以同步方式运行。请考虑使用 'await' 操作符等待非阻塞 API 调用,或者使用 'await Task.Run(...)' 在后台线程上执行 CPU 绑定的工作。

我做错了什么吗?我的代码可以正常运行,我能够下载 Excel 文件。

1个回答

68

我做错了什么吗?

嗯,你并没有真正地异步处理任何内容。你的 ReportExcelAsync 方法完全是同步的,因为它没有任何 await 表达式。因此,GenerateReportExcel 将调用 ReportExcelAsync,它将同步运行,然后返回已完成的任务。你目前所做的只是增加了一小部分开销,用于创建状态机等实现 async/await 的代码。

不清楚你为什么期望它实际上会异步执行,但我怀疑这是对 await/async 实际上做了什么的误解。它并不会自动为你启动新线程——它只是使得创建和使用异步 API 更加容易。

现在有一个选项是想要将 ReportExcelAsync 更改为同步方法(ReportExcel,返回一个 string),并在调用代码中创建一个新任务:

var filePath = await Task.Run(excel.ReportExcel);

然而,这并不能明确地给你带来多少好处。你正在编写一个 Web 应用程序,因此响应不会更快地交付 - 你实际上只是将工作线程进行了转移

你说:

由于我需要它异步完成

...但没有说明为什么必须异步处理。在这种情况下,同步方法有什么问题吗?当异步合适时,异步是很好的选择,但我认为在你的情况下它并不适用。


2
这行代码 var filePath = await excel.ReportExcelAsync(midyearReportViewModel); 不就是在执行吗?第二行。 - stevethethread
3
如果ReportExcelAsync确实是异步的,那么这将是异步执行事务 - 但它不是。这个方法生成警告,因为它没有任何await表达式。 - Jon Skeet
4
我猜你对“异步”这个词的理解和我不太一样。你所做的一切都是同步的——你期望它在哪里变成异步,并且你期望获得什么具体的好处呢?你真正想要解决的是什么问题? - Jon Skeet
3
为什么要使用异步编程?你仍然需要进行同样数量的工作,而且所有工作都在本地完成。这并不像你会释放任何线程一样。感觉你认为异步编程可以解决所有问题,但实际上并非如此。你需要思考异步编程将从哪里带来真正的异步性。比如,如果你可以从数据库异步地获取数据,或者执行异步IO操作,那么可能可以减少所需的线程数 - 但否则我认为它不会帮助你。你现在是否真的有性能问题? - Jon Skeet
1
@Skeet 并不完全是这样。目前可能有30-40个用户,最多可能增加到200-300个。感谢您的澄清。 - Jayason
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接