34

I have a excel download in my asp.net mvc 4 application. When I click the export button the below controller method gets called. Since I need it to be done asynchronous, I am using async and await here.

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

This method inturn call a excel generator method ReportExcelAsync as shown below

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

But I get a warning message as Warning

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread

. Am I doing something wrong ?.My code works fine and I am able to get the excel downloaded.

Jayason
  • 345
  • 1
  • 3
  • 6

1 Answers1

68

Am I doing something wrong?

Well, you're not really doing anything asynchronously. Your ReportExcelAsync method is entirely synchronous, as it doesn't have any await expressions. So GenerateReportExcel will call ReportExcelAsync, which will run synchronously, and then return a completed task. All you've done at the moment is add a small amount of overhead for creating the state machine etc that is used to implement async/await.

It's not clear why you expected it to actually happen asynchronously, but I suspect it's a misunderstanding of what await/async actually does. It doesn't start up new threads for you automatically - it just makes it much easier to create and consume asynchronous APIs.

Now one option is to just want to change ReportExcelAsync into a synchronous method (ReportExcel, returning a string) and create a new task for that in the calling code:

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

However, it's not clear that this would actually give you much benefit. You're writing a web app, so it's not like the response is going to be delivered any faster this way - you're effectively just shifting the thread the work is done on.

You say:

Since I need it to be done asynchronous

... but give no reasons why it needs to be done asynchronously. What's wrong with the synchronous approach in this case? Asynchrony is great when it's appropriate, but I don't think it is in your case.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Isn't what this line var filePath = await excel.ReportExcelAsync(midyearReportViewModel); is doing? 2nd Line. – stevethethread Jan 23 '14 at 08:43
  • 3
    @stevethethread: That would be doing things asynchronously *if* `ReportExcelAsync` were really asynchronous - but it's not. That's the method that generates the warning, because it has no `await` expressions. – Jon Skeet Jan 23 '14 at 08:45
  • @Skeet My aim was to generate the excel and return the path asynchronously. – Jayason Jan 23 '14 at 08:47
  • +1 for truth. Async isn't a magic wand to make things asynchronous. – Greg D Jan 23 '14 at 08:47
  • Sure, I see what you're saying – stevethethread Jan 23 '14 at 08:47
  • 4
    @user2988112: I suspect your understanding of the word "asynchronously" isn't the same as mine. Everything you're doing is synchronous - where did you expect the asynchrony to come in, and what concrete benefit did you expect it to have? What *problem* are you actually trying to solve here? – Jon Skeet Jan 23 '14 at 08:48
  • I was thinking if we make it async, it would be better if there are more request coming. – Jayason Jan 23 '14 at 08:51
  • 3
    @user2988112: Why? You still have just as much work to do, and it's all being done locally. It's not like you'd be freeing up any threads. It feels like you're thinking of async as a magic bullet - it's really not. You've got to think about where the actual asynchrony would come from. For example, if you could asynchronously fetch the data from a database, or perform asynchronous IO that could reduce the number of threads you need - but otherwise I don't think it's going to help you. Do you actually *have* a performance issue at the moment? – Jon Skeet Jan 23 '14 at 08:52
  • 1
    @Skeet Not really. Currently there might be 30-40 user which might rise to 200-300 at the max. Thanks for your clarification. – Jayason Jan 23 '14 at 08:57