Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What effect does using LegacyAspNetSynchronizationContext have with async / await code in .net 4.7?

I'm upgrading a legacy Asp.Net WebForms project to .net 4.7.

In my configuration I set the target framework to 4.7 and synchronization context to use the new AspNetSynchronizationContext (although I believe the latter is implied if omitted) to allow new async / await methods to work e.g.

<httpRuntime targetFramework="4.7" />
...
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

But then I found lots of code along the lines of the following:

var myTask = DoSomethingAsync();
return myTask.Result;

The result of the task is not being awaited which causes the app to hang.

If I change my configuration to use the LegacyAspNetSynchronizationContext ...

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />

... the legacy non-awaited code works again and the new async/await methods appear to work. I say "appear" as I read in this MSDN article that:

the behavior of async / await is undefined in ASP.NET unless this switch has been set

Why is it undefined? Does this mean the behaviour is unpredictable or just won't work?

If I have a snippet of code like the following what will or could happen when it is called in a LegacyAspNetSynchronizationContext?

public async Task<bool> DoSomethingElseAsync()
{
    return await CallSomeApiAsync().ConfigureAwait(false);
}
like image 341
Gavin Sutherland Avatar asked Dec 09 '25 21:12

Gavin Sutherland


1 Answers

Using the LegacyAspNetSynchronizationContext means you don't get a defined behaviour when using tasks; the legacy synchronization model was not built to work with task-scheduling. You must use the new synchronization context if you want to use tasks inside ASP.NET.

var myTask = DoSomethingAsync();
return myTask.Result;

This code blocks on a Task. Calling Wait() or Result on a running Task will block the calling thread until the Task completes.

You can't safely block on tasks unless you know:

  • The task has already completed (in which case you're not really blocking).
  • The synchronization context will not attempt to resume on the same thread the task started on.

The only reasonable solution is to use tasks all the way down. Any methods which attempt to block on a Task should instead be changed to return a Task or Task<TResult> and await the running Task instead.

like image 77
Paul Turner Avatar answered Dec 11 '25 11:12

Paul Turner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!