0

My question is involving a web api I created using asp.net/c# and is deployed to an Azure server. The API basically gets a requests to process an image with some text printed over it.

I have a method that is called once a get request is received. In english, the method does some setup, then downloads the proper image requested from Azure blob storage, then does the drawing.

public HttpResponseMessage process(string image){

DoSomeSetup();  

DownloadFromBlob(image);

return DrawTextOnImage();
}

My problem is that downloading from the Azure blob takes the longest time out of all the operations, usually 2-3 seconds. I figure that it would be much more efficient if I could download the image WHILE setup is occurring, in order to save time.

public HttpResponseMessage process(string image){

startDownloadingImageFromBlob(image);

DoSomeSetup();

EnsureImageDownloadFinished();

return DrawTextOnImage();
}

I am under the impression that simply calling

Bitmap templateImage = DownloadImageFromUrl(BLOB_STORAGE_TEMPLATES_BASE_URL)

at the top of the method will wait for the download to complete before moving onto the setup. Is there a way that I can get the download to happen at the same time as setup, and then (if necessary) wait for it to finish before drawing?

JakeD
  • 407
  • 2
  • 7
  • 19
  • Unless `DoSomeSetup()` is also IO bound or particularly CPU intensive, chances are you will actually see a (imperceivable) performance decrease by trying to to the download asynchronously. – w.brian Jan 04 '17 at 20:43

2 Answers2

2

You should not use Wait or Task.Run on ASP.NET.

Since a download is an I/O-based operation, an asynchronous approach makes the most sense. The first thing to do is identify which APIs are being called by DownloadFromBlob, change them to their asynchronous equivalents, and call them using await. Then allow async to grow from there (the compiler will guide you). Eventually, you'll end up with something like:

async Task<Bitmap> DownloadFromBlobAsync(string image);

And at this point, you can start the download by invoking (but not awaiting) the method, and then await the task after your setup is done:

public async Task<HttpResponseMessage> process(string image)
{
  var task = DownloadFromBlobAsync(image);
  var setupData = DoSomeSetup();
  var image = await task;
  return DrawTextOnImage(image, setupData);
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
0

You can spawn a task to execute in parallel then wait for the task to complete before continuing. Something like this:

// using System.Threading.Tasks;
public HttpResponseMessage process(string image) {

   var downloadTask = Task.Run(() => {
       DownloadFromBlob(image);
    });

   DoSomeSetup();  

   downloadTask.Wait();

   return DrawTextOnImage();
}

Reference: MSDN Task Class

Wagner DosAnjos
  • 6,304
  • 1
  • 15
  • 29
  • looks like this is exactly what I was looking for. I will do some performance testing and see if this works as expected. If it does I will report back and accept the answer. Thanks! – JakeD Jan 04 '17 at 20:13
  • 5
    but downloading is an IO operation. isn't there an asynchronous download method that does not need another extra thread? – René Vogt Jan 04 '17 at 20:14
  • 1
    OP is likely not experienced enough to see trolling attempt with call to .Wait on a task in Asp.net... – Alexei Levenkov Jan 04 '17 at 20:17
  • ^ apparently not.. care to explain? – JakeD Jan 04 '17 at 20:18
  • Take a look at the async methods in HttpClient. Good example here: https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client – dcrobbins Jan 04 '17 at 20:25
  • 1
    My understanding is that it's not a good idea to use `Task.Run` in an ASP.NET application...at least not for I/O-bound operations. In other words, what René states. – Kenneth K. Jan 04 '17 at 20:37
  • Assuming there is actually something to be gained by doing the `DownloadByBlob` asynchronously, the `process` method itself should be marked as `async Task` and the `DownloadFromBlob` should also be refactored to return a task, and then invoked using `await`. – w.brian Jan 04 '17 at 20:45