0

While reading this question the accepted answer appears to be incorrect as stated by an answer below it and this article that followed. It states that you should wait for ReadAsByteArrayAsync to be complete before continuing with the log due to the fact the Model binder will return null since they are both reading at the same time.

So the accepted solution is:

if (request.Content != null)       
    {           
        request.Content.ReadAsByteArrayAsync()               
        .ContinueWith(task =>                   
        {                       
            var result = Encoding.UTF8.GetString(task.Result);
            // Log it somewhere                   
        })
    }  

But the correct solution should be:

if (request.Content != null)       
    {           
        request.Content.ReadAsByteArrayAsync()               
        .ContinueWith(task =>                   
        {                       
            var result = Encoding.UTF8.GetString(task.Result);
            // Log it somewhere                   
        }).Wait(); // Wait until ReadAsByteArrayAsync is completed
    }   

Now I'm a bit confused as to why the wait really needs to occur, my understanding is continueWith does wait until the task beforehand has completed, then continues. Is there something here I am missing, or don't quite understand about tasks and continues?

Community
  • 1
  • 1
dbarnes
  • 1,803
  • 3
  • 17
  • 31
  • 1
    using `Task.Wait` doesn't really run the method asynchronously. It will block until the method completes, which is like running it completely synchronously. – Yuval Itzchakov Sep 28 '14 at 18:18

2 Answers2

3

The reason why the Wait needs to be done is because if you don't call it, then the method will return immediately and continue with the execution. Then if the model binder attempts to read the request.Content while your first call hasn't finished, it may fail.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • So it's purely a race condition issue here? Where this task gets executed but the model binder is also executing? – dbarnes Sep 28 '14 at 18:19
  • Correct, the model binder that needs to read the request content might run at the same time. – Darin Dimitrov Sep 28 '14 at 18:21
  • 1
    That's what I figured I just wanted someone to confirm it. – dbarnes Sep 28 '14 at 18:25
  • To be clear, `Wait` doesn't have to be directly called by us.. The issue is being confused with only one thing.. Synchronous API is what is needed here, and `HttpContent` doesn't provide one. But that doesn't mean the continuation and Wait have to be explicitly coded. See the answer below for alternate, more compact and clearer code.. – Vikas Gupta Sep 28 '14 at 18:52
0

I'd write the above code as following -

if (request.Content != null)       
{           
    var task = request.Content.ReadAsByteArrayAsync();
    // Task.Result waits until Async operation is completed.
    // http://msdn.microsoft.com/en-us/library/dd321468(v=vs.110).aspx
    var result = Encoding.UTF8.GetString(task.Result);
}
Vikas Gupta
  • 4,455
  • 1
  • 20
  • 40