Executing synchronous methods asynchronously
We can achieve certain advantages by writing asynchronous methods. It's pretty simple to write them in C# code: we just need to use async and await keywords properly. Grammar of these keywords can be found in detail in MSDN. In this post I will try to focus on writing few code to invoke a regular synchronous method asynchronously.
Let's assume a scenario where we need to perform an expensive database operation when a particular information is changed from the front end.
For example: I have an application to manage employee information and I've changed the basic salary for a particular grade using my application. Now I need to update salary of all the employees under that grade. The later operation will be slower one and I don't want this to block me from doing other stuffs.
Here is a piece of synchronous code to update salary information:
Now I will be invoking this synchronous operation within an asynchronous method so that this operation is executed asynchronously i.e. without blocking the user:
Notice that, SynchronizeSalaryInformationAsync will wait for salary data synchronization, but the control flow will immediately return to the end of the function after invoking the Task.
Now the final task is to call this asynchronous method after regular update of grade information. Here is how we can do that:
So, basically SaveGrade() method will be executing in the following sequence:
But executing the last piece of code is likely to throw NullReference exception probably with the following stack trace:
This is because, when an async method is executed, it attempts to return back to the parent thread in its calling context which might have switched by another user action. To avoid this we can slightly modify the code as in below:
Now we are assuring that the async method will return to its orphan parent thread and thereby will not throw any NullReference exception.
Let's assume a scenario where we need to perform an expensive database operation when a particular information is changed from the front end.
For example: I have an application to manage employee information and I've changed the basic salary for a particular grade using my application. Now I need to update salary of all the employees under that grade. The later operation will be slower one and I don't want this to block me from doing other stuffs.
Here is a piece of synchronous code to update salary information:
public bool UpdateEmployeeSalary(string grade) { try { //logic for an expensive operation using (var newConn = new SqlConnection(GetConnectionStringFromConfig())) { newConn.Open(); using (var sqlCommand = newConn.CreateCommand()) { sqlCommand.Connection = newConn; sqlCommand.CommandText = "spUpdateEmployeeSalary"; sqlCommand.CommandType = CommandType.StoredProcedure; sqlCommand.Parameters.AddWithValue("Grade", grade); sqlCommand.CommandTimeout = 0; // operation might take longer sqlCommand.ExecuteNonQuery(); } } } catch (Exception ex) { //log error } return true; }
Now I will be invoking this synchronous operation within an asynchronous method so that this operation is executed asynchronously i.e. without blocking the user:
public virtual async Task<bool> SynchronizeSalaryInformationAsync(string grade) { var service = ServiceFactory.Get<IEmployeeService>(); return await Task.Run(() => service.UpdateEmployeeSalary(grade)); }
Notice that, SynchronizeSalaryInformationAsync will wait for salary data synchronization, but the control flow will immediately return to the end of the function after invoking the Task.
Now the final task is to call this asynchronous method after regular update of grade information. Here is how we can do that:
public void SaveGrade(Grade model) { // regular update operation UpdateGradeInformation(model); // asynchronous update operation SynchronizeSalaryInformationAsync(model.Title); // other stuffs to do... }
So, basically SaveGrade() method will be executing in the following sequence:
- UpdateGradeInformation() will be executed and completed.
- SynchronizeSalaryInformationAsync() will start asynchronously.
- The rest of the code will execute regardless of completion of the async method.
But executing the last piece of code is likely to throw NullReference exception probably with the following stack trace:
System.Web.dll!System.Web.ThreadContext.AssociateWithCurrentThread(bool setImpersonationContext = {unknown}) C#
System.Web.dll!System.Web.HttpApplication.OnThreadEnterPrivate(bool setImpersonationContext = {unknown}) C#
System.Web.dll!System.Web.HttpApplication.OnThreadEnter() C#
System.Web.dll!System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter() C#
System.Web.dll!System.Web.Util.SynchronizationHelper.SafeWrapCallback(System.Action action = {unknown}) C#
System.Web.dll!<>c__DisplayClass9.AnonymousMethod(System.Threading.Tasks.Task _ = {unknown}) C#
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke() C#
mscorlib.dll!System.Threading.Tasks.Task.Execute() C#
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj = {unknown}) C#
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext = {unknown}, System.Threading.ContextCallback callback = {unknown}, object state = {unknown}, bool preserveSyncCtx = {unknown}) C#
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext = {unknown}, System.Threading.ContextCallback callback = {unknown}, object state = {unknown}, bool preserveSyncCtx = {unknown}) C#
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot = {unknown}) C#
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution = {unknown}) C#
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() C#
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() C#
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() C#
This is because, when an async method is executed, it attempts to return back to the parent thread in its calling context which might have switched by another user action. To avoid this we can slightly modify the code as in below:
public void SaveGrade(Grade model) { // regular update operation UpdateGradeInformation(model); // asynchronous update operation Task.Run(async () => { await SynchronizeSalaryInformationAsync(model.Level); }); }
Now we are assuring that the async method will return to its orphan parent thread and thereby will not throw any NullReference exception.
Pleasant Tips..Thanks for Sharing….We keep up hands on approach at work and in the workplace, keeping our business pragmatic, which recommends we can help you with your tree clearing and pruning in an invaluable and fit way.
ReplyDeletepython Training in Pune
python Training in Chennai
python Training in Bangalore
Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
ReplyDeletepython Training in Pune
python Training in Chennai
python Training in Bangalore
I appreciate that you produced this wonderful article to help us get more knowledge about this topic. I know, it is not an easy task to write such a big article in one day, I've tried that and I've failed. But, here you are, trying the big task and finishing it off and getting good comments and ratings. That is one hell of a job done!
ReplyDeleteData Science course in kalyan nagar
Data Science course in OMR
Data Science course in chennai
Data science course in velachery
Data science course in jaya nagar
Data Science interview questions and answers
Data science course in bangalore