【问题标题】:How to use async/await on void methods in ASP.NET Core?如何在 ASP.NET Core 中的 void 方法上使用 async/await?
【发布时间】:2019-07-22 19:26:45
【问题描述】:

我正试图进入异步的东西。我想让我的一个方法异步,因为它需要一段时间才能完成,所以我尝试了这个:

public static async Task GenerateExcelFile(HashSet<string> codes, ContestViewModel model)
{
    var totalCodeToDistribute = model.NbrTotalCodes - (model.NbrCodesToPrinter + model.NbrCodesToClientService);
    if (model.NbrTotalCodes > 0)
    {
        using (var package = new ExcelPackage())
        {
                         
            await DoStuff(some, variables, here);
                        
            package.SaveAs(fileInfo);
        }
    }
}

所以我可以在我的控制器中这样调用它:

 await FilesGenerationUtils.GenerateExcelFile(uniqueCodesHashSet, model);

但是当涉及到“await”关键字时,它表示“Type void is not awaitable”

这是等待 void 方法的一种方式还是不是最佳实践?如果是这样,最好的方法是什么?

控制器:

[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Index(ContestViewModel model)
        {
            var contentRootPath = _hostingEnvironment.ContentRootPath;

            DirectoryUtils.OutputDir = new DirectoryInfo(contentRootPath + Path.DirectorySeparatorChar
                                                                         + "_CodesUniques" + Path.DirectorySeparatorChar
                                                                         + model.ProjectName +
                                                                         Path.DirectorySeparatorChar
                                                                         + "_Codes");
            var directory = DirectoryUtils.OutputDir;

            var selectedAnswer = model.SelectedAnswer;

            var uniqueCodesHashSet = new HashSet<string>();

            try
            {
                
                while (uniqueCodesHashSet.Count < model.NbrTotalCodes)
                {
                    var generatedString = RandomStringsUtils.Generate(model.AllowedChars, model.UniqueCodeLength);
                    uniqueCodesHashSet.Add(generatedString.ToUpper());
                }

                #region FOR TXT FILES

                if (selectedAnswer == FileExtension.TXT.GetStringValue())
                {
                   await FilesGenerationUtils.GenerateTxtFiles(uniqueCodesHashSet, model, directory);
                }

                #endregion

                #region FOR XLSX FILES

                if (selectedAnswer == FileExtension.XLSX.GetStringValue())
                {
                    await FilesGenerationUtils.GenerateExcelFile(uniqueCodesHashSet, model);
                }

                #endregion
             
       
                return View();
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }

            return View();
        }

如果我理解了你们所说的,我必须创建一个可以等待的方法。如果我使用这样的东西,我会正确吗:

public static Task DoStuff(ExcelWorksheet sheet, HashSet<string> codes, int rowIndex, int count, int maxRowValue)
        {
            foreach (var code in codes)
            {
                sheet.Row(rowIndex);
                sheet.Cells[rowIndex, 1].Value = code;
                rowIndex++;
                count++;
                if (rowIndex == maxRowValue && count < (codes.Count - 1))
                {
                    sheet.InsertColumn(1, 1);
                    rowIndex = 1;
                }
            }
            //What should be returned?!
            return null;
        }

【问题讨论】:

  • 您的返回类型指定为Task
  • 你必须返回一个等待对象。
  • 你能显示你的控制器方法的代码吗?
  • 您显示的代码没有返回void;它返回Task。你不应该得到你正在谈论的那个代码的错误。
  • 是的,问题是package.SaveAs 不是异步方法,它不可能是awaited。简而言之,你的“DoStuff()”方法需要变成异步的,你需要等待那个。一般来说,这样做的需要是深入了解所有方法调用,直到找到对“开箱即用”异步方法的调用,例如与文件或网络一起使用的方法。跨度>

标签: c# asp.net-core asynchronous async-await


【解决方案1】:

您可以编写异步 void 方法,但不能等待这些方法:

public static class Program
{
    public static async Task Main()
    {
        const int mainDelayInMs = 500;
        AsyncVoidMethod();
        await Task.Delay(mainDelayInMs);
        Console.WriteLine($"end of {nameof(Main)}");
    }

    static async void AsyncVoidMethod()
    {
        await Task.Delay(1000);
        Console.WriteLine($"end of {nameof(AsyncVoidMethod)}");
    }
}

如您所见,AsyncVoidMethod 是异步的,但我不能写 await AsyncVoidMethod();

(大多数情况下)不应该使用异步 void 方法,因为您不能等待任务完成,并且可能无法处理抛出的任何异常(因此它可能会使您的应用程序崩溃):Why exactly is void async bad?

【讨论】:

  • 感谢您的时间@asidis。我已经编辑了我的原始帖子,以显示我现在正在阅读你的方向。我走对了吗?如果是这样,新的 async DoStuff() 方法应该返回什么?...我正在努力解决我猜想的那些任务
  • 我认为这里的误解是您可以简单地决定使任意方法异步,但事实并非如此。在大多数情况下,异步“开始”是调用 .NET 基类库方法,该方法使用操作系统中的设施来提供真正的异步。这通常是做 I/O 的东西,比如FileStream.ReadAsync()awaits 在该调用上的方法返回 Task,然后其他方法可以等待 that 方法并返回 Tasks。这可以在您的应用程序中一直传播,因此您的大多数方法都使用并返回 Tasks。
【解决方案2】:

当你的方法在后台阻塞时,假装你的方法是异步的通常没有什么好处。如果你需要一个任务,你可以在 Task.Run 中包装阻塞方法来创建一个等待任务。您仍将使用和阻塞线程,而不是当前线程。

推荐阅读:https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html

【讨论】:

    猜你喜欢
    • 2013-10-02
    • 1970-01-01
    • 2022-12-17
    • 2013-05-26
    • 1970-01-01
    • 2018-06-29
    • 2019-03-15
    • 2021-01-25
    • 1970-01-01
    相关资源
    最近更新 更多