Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use async/await on void methods in ASP.NET Core?

I'm trying to get into the asynchronous thing. I'd like to make one of my methods asynchronous because it takes a while to finish so I tried this:

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);
        }
    }
}

So I could call it in my controller like that:

 await FilesGenerationUtils.GenerateExcelFile(uniqueCodesHashSet, model);

but when it comes to the "await" keyword, it says that "Type void is not awaitable"

Is that a way to await for void methods or is it not a best practice? And if so, what would be the best way to do it?

The controller:

[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();
        }

If I've understood what you're all saying, I must create a method that would be awaitable. Am I going right if I go with something like this:

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;
        }
like image 510
j0w Avatar asked Dec 23 '22 00:12

j0w


1 Answers

You can write async void methods but these cannot be awaited:

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)}");
    }
}

As you can see AsyncVoidMethod is async but I cannot write await AsyncVoidMethod();.

Async void methods should (most of the time) not be used as you cannot wait for completion of the task and any exception thrown may not be handled(and so it can crash your application): Why exactly is void async bad?

like image 64
asidis Avatar answered Dec 25 '22 13:12

asidis