web-dev-qa-db-fra.com

Message d'avertissement dans la méthode async indiquant qu'il manque d'attendre les opérateurs

J'ai un téléchargement Excel dans mon application asp.net mvc 4. Lorsque je clique sur le bouton d'exportation, la méthode de contrôleur ci-dessous est appelée. Puisque j'ai besoin que cela se fasse de manière asynchrone, j'utilise async et j'attends ici.

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

Cette méthode appelle à son tour une méthode de générateur Excel ReportExcelAsync comme indiqué ci-dessous

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

Mais je reçois un message d'avertissement comme avertissement

Cette méthode asynchrone manque d'opérateurs "en attente" et s'exécutera de manière synchrone. Envisagez d'utiliser l'opérateur 'wait' pour attendre les appels d'API non bloquants, ou 'wait Task.Run (...)' pour effectuer un travail lié au processeur sur un thread d'arrière-plan

. Suis-je en train de faire quelque chose de mal? .Mon code fonctionne bien et je peux télécharger Excel.

32
Jayason

Est-ce que je fais quelque chose de mal?

Eh bien, vous ne faites rien de manière asynchrone. Votre méthode ReportExcelAsync est entièrement synchrone, car elle n'a pas d'expressions await. Ainsi, GenerateReportExcel appellera ReportExcelAsync, qui s'exécutera de manière synchrone, puis renverra une tâche terminée. Tout ce que vous avez fait pour le moment, c'est ajouter une petite quantité de surcharge pour créer la machine d'état, etc., qui est utilisée pour implémenter async/await.

La raison pour laquelle vous vous attendiez à ce que cela se produise de manière asynchrone n'est pas claire, mais je soupçonne que c'est une mauvaise compréhension de ce qui attend/async. Il ne fait pas démarrer automatiquement de nouveaux threads - cela facilite la création et la consommation d'API asynchrones.

Maintenant, une option consiste à vouloir simplement changer ReportExcelAsync en une méthode synchrone (ReportExcel, renvoyant un string) et créer une nouvelle tâche pour cela dans le code appelant:

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

Cependant, il n'est pas clair que cela vous apporterait réellement beaucoup d'avantages. Vous écrivez une application web, donc ce n'est pas comme si la réponse allait être livrée plus rapidement de cette façon - vous êtes en fait juste shifting le thread sur lequel le travail est effectué.

Vous dites:

Puisque j'ai besoin que cela se fasse de manière asynchrone

... mais ne donnez aucune raison pourquoi cela doit être fait de manière asynchrone. Quel est le problème avec l'approche synchrone dans ce cas? L'asynchronie est géniale lorsqu'elle est appropriée, mais je ne pense pas que ce soit dans votre cas.

63
Jon Skeet