Async and HttpContext

Things get complicated when there are threads involved and a little bit more complicated when there is no thread i.e async.

You might have come across this function - ConfigureAwait(bool). It's a life savior. CLR does not guarantee that once an async operation completes, it will continue on the same thread on which code was running before starting an async operation. If you pass false to ConfigureAwait(bool) then it will grab another thread from the threadpool and continue execution on that thread without restoring the context, in case of true, it will continue execution on the same thread, restore the context, and resumes execution of sync code.

Why does execution context matters? If you like to have access to HttpContext and also perform async operations then context matters, as these operations might execute on different threads and you will lose access to data for not being carried over from one thread to another.

Solution -

var getProcessStatusByVisitTask = Task.Factory.StartNew(() => this._visitService.GetProcessStatusByVisit(visitInfo.SystemKey, facilityCode, _visitService.TabStatus, visitInfo.HospitalServiceLocation), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
var activitiesTask = Task.Factory.StartNew(() => _iActivityService.Activities(visitNumber, visitInfo.SystemKey, facilityCode, this._visitService.IsMedicalNecessisty), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
await Task.WhenAll(getProcessStatusByVisitTask, activitiesTask).ConfigureAwait(true);

Notice TaskScheduler.FromCurrentSynchronizationContext() call, it means it's going to run the above async calls inside the context carried over from current threads. So, you will have access to your current environment i.e session, httpcontext etc.

When you have multiple methods, it's better to await them all together, instead of one-by-one. Otherwise, there will be a lot of back and forth between sync and async code.

Let's go behind the scenes -

A big question might be coming to your mind - What actually async\await does? Async prepares the infrastructure so that we can use await. You might be surprised to know that CLR does not even know these keywords. 

It's worth mentioning that await cannot be used if the method's signature is missing async.

For illustration purposes, I added the following line of code and C# compiler generated the code shown in the below two images.

public async void Test() { }

In the first image, you can see the Test() method at the very top. Rest of the code is StateMachine, which will be used to run async code. Inside the second image, there is a second last method - MoveNext(), it will contain your async code.

Image 1 :

Image 2:

 

Precautionary Measures:

1. Remember to await on the task. Otherwise, it will just run synchronously. This is a hot task which means it's running in the background.

2. Await on an async operation can be delayed if you like to run a task in the background and in no mood to relinquish control and also perform a synchronous operation. This is a bit situational scenario.

3. Do not wait on the async method. It will cause a deadlock

4. If you are calling multiple async methods in an async container method then it's better to collectively await on all of them using Task.WhenAll instead of individually. It will result in better performance

5. Better to make it async all the way from first caller to the last call, otherwise it's just partial implementation

 

I will publish couple more blogs to go a bit deeper inside async StateMachine. Till then, take care.

 

Happy Coding.

   

Further Reading -

1. https://softwareengineering.stackexchange.com/questions/187492/why-do-we-need-the-async-keyword

2. https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth

3. https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async

4. https://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code

5. http://foreverframe.net/what-lies-beneath-asyncawait-in-c/

 

Add comment