StephenCleary / AsyncEx

A helper library for async/await.
MIT License
3.51k stars 358 forks source link

Is it safe to use with WebForms? #227

Closed jahav closed 3 years ago

jahav commented 3 years ago

Wiki talks only about Console apps, so I am asking fro webforms.

My situation:

I have found WebForms way to call async task rather unpleasant to work with (and rather hard to migrate), but I would like to use same way to use async code as in more modern parts of the app.

The question: If I take a former static method in a webform page and replace it with a an async call through AsyncContext.Run, will it work (=no strange deadlocks down the line, weird interaction with whatever synch. context Webforms have)?

Performance is not an issue (admin portal is used by a small single digit number number of users).

StephenCleary commented 3 years ago

It may or may not work, depending on what exactly the method does.

The way AsyncContext works is that it installs its own SynchronizationContext and uses that to schedule async continuations on the same thread by default (and also to detect when all async void methods have completed). So it avoids the normal deadlock you would see when blocking on asynchronous code (by using the blocked thread to run the continuations). But it also does replace the AspNetSynchronizationContext with its own.

This has caused problems for some ASP.NET MVC methods; some of them depend on an AspNetSynchronizationContext and they just hang if it's not the current sync context. And this isn't documented anywhere. So as a general rule, I don't mess with SynchronizationContext.Current (or use AsyncContext) for any code that calls ASP.NET MVC methods. I would assume the same would hold true for WebForms: I'd expect some methods would depend on AspNetSynchronizationContext and would not work correctly when it's not current.

So, if your static methods don't call any WebForms methods, then I'd say it would be safe. Though in that case, you could just as easily call Task.Run and then call GetAwaiter().GetResult() on the returned task.