Using Async, Await, Plus a Slight Delay?

catrina - Apr 5 '18 - - Dev Community

Today’s problem dealt with how we view our invoices online. We use an app on the iSeries that creates a PDF and delivers it to a set destination. That destination, in our case is a regular windows server, the files landing in a small site: pdf.mycompany.com.

My initial approach was simple, use the PHP API I have sitting on the iSeries to make a call to the program – passing it the parameters for that specific invoice, await response (which gave me the new created filename) and then redirect to that URL. The method looks something like this:

[HttpGet]
public async Task<ActionResult> GetInvoiceAsync(int invoice)
{
    GetInvoice getInvoice = new GetInvoice();
    var client = new HttpClient();

    string fileName = await getInvoice.LoadPDF(invoice);

    string url = "http://pdf.mycompany.com/";
    url += fileName + ".pdf";

    return Redirect(url);
}
Enter fullscreen mode Exit fullscreen mode

This worked great… 90% of the time, but the other 10% of the time, I clicked too quickly on an invoice and got forwarded to a 404.

The Confusion

LoadPDF is an async method, sitting in my Services folder and the method above sits in my controller. I assumed, because it was an await, well, GetInvoiceAsync should WAIT until the server is done. So, then, why am I getting forwarded prematurely? Why is it not waiting?

The Real Problem

GetInvoiceAsync IS waiting, it is waiting for a response.

What was really happening:

  • LoadPDF takes data, seralizes it.
  • LoadPDF creates a HttpWebRequest and posts the data to the iSeries
  • The iSeries responds with a file name
  • RESPONSE IS MADE. AWAIT IS OVER
  • User is forwarded to new file
  • iSeries is still in the process of copying file over
  • User gets a 404

Easy Solution

I solved the problem by simply adding a small delay inside of LoadPDF. So, it gets response, then waits another 1.5 seconds before confirming to the controller it is done. Here’s the code that solved it:

//declared at top of class
CancellationTokenSource source = new CancellationTokenSource();

//iSeries needs time to copy file over to pdf server
//added in LoadPDF just before return(fileName);
await Task.Delay(TimeSpan.FromSeconds(1.5), source.Token);
Enter fullscreen mode Exit fullscreen mode

Do you know a better way I can handle this?

. . . . . . . . . . . . . . . . . . .