Request.Content.ReadAsMultipartAsync never returns

Solution 1:

I ran into something similar in .NET 4.0 (no async/await). Using the debugger's Thread stack I could tell that ReadAsMultipartAsync was launching the task onto the same thread, so it would deadlock. I did something like this:

IEnumerable<HttpContent> parts = null;
Task.Factory
    .StartNew(() => parts = Request.Content.ReadAsMultipartAsync().Result.Contents,
        CancellationToken.None,
        TaskCreationOptions.LongRunning, // guarantees separate thread
        TaskScheduler.Default)
    .Wait();

The TaskCreationOptions.LongRunning parameter was key for me because without it, the call would continue to launch the task onto the same thread. You could try using something like the following pseudocode to see if it works for you in C# 5.0:

await TaskEx.Run(async() => await Request.Content.ReadAsMultipartAsync(provider))

Solution 2:

I came across the same problem with all modern 4.5.2 framework.

My API method accepts one or more files uploaded using POST request with multipart content. It worked fine with small files, but with big ones, my method just hanged forever because the ReadAsMultipartAsync() function never completed.

What helped me: using an async controller method and await for the ReadAsMultipartAsync() to complete, instead of getting the task result in a synchronous controller method.

So, this did not work:

[HttpPost]
public IHttpActionResult PostFiles()
{
    return Ok
    (
        Request.Content.ReadAsMultipartAsync().Result

        .Contents
        .Select(content => ProcessSingleContent(content))
    );
}

private string ProcessSingleContent(HttpContent content)
{
    return SomeLogic(content.ReadAsByteArrayAsync().Result);
}

And this worked:

[HttpPost]
public async Task<IHttpActionResult> PostFiles()
{
    return Ok
    (
        await Task.WhenAll
        (
            (await Request.Content.ReadAsMultipartAsync())

            .Contents
            .Select(async content => await ProcessSingleContentAsync(content))  
        )
    );
}

private async Task<string> ProcessSingleContentAsync(HttpContent content)
{
    return SomeLogic(await content.ReadAsByteArrayAsync());
}

where SomeLogic is just a synchronous function taking binary content and producing a string (can be any kind of processing).

UPDATE And finally I've found the explanation in this article: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock.

So, basically, the “Async all the way” guideline has a reason behind it, and this is a good example.

Solution 3:

With help of another answer on stackoverflow and a blog post about targetFramework, I've found that updating to 4.5 and adding/updating the following in your web.config fixes this issue:

<system.web>
    <compilation debug="true" targetFramework="4.5"/>
</system.web>
<appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>