Working with async/await in .Net 4.8

Why should we use the async method?

The await word provides the feature that allows other processes to continue asynchronously while waiting for the task to finish its job, that is, non-blocking.

For example, when you make an asynchronous web service request, ASP.NET will not use threads between the async method call and the await. It prevents thread starvation.

Authoring Async Methods

  1. async Task MyMethod() { }
    which creates a method that can be awaited, but does not return any value,

  2. async Task<T> MyReturningMethod { return default(T); }
    which creates a method that can be awaited, and returns a value of the type T,

  3. private async void Button1_Click(object sender, EventArgs args) { }
    async void methods are only suited for UI event handlers

Method 1:
If you want to call a method whose return value is Task, it is sufficient for the current method to start with async.

async MyMethod1
await MyMethod2
async Task MyMethod2

Method 2:
If you need to "call a synchronous method" that does not return Task and you are in a method labeled async, you can use Task.Run. A new thread is opened on the compiler side and the code is run in this thread. Another important point here is that Task.Run can be used with await since it will return Task.

async MyMethod1
await Task.Run(() => { MyMethod2 }
void MyMethod2 (normal method. sync)

public static async Task PushNeworder(string[] deviceIds, string message, string header, string isLogout, object payload)
{
    await Task.Run(() =>
    {
       // sync method
       PushToFirebase(deviceIds, isLogout, message, header, payload);
    });
}

If you want to return value;

public static async Task<string> AsyncPostData(string apiURL, string data, bool isNETGM)
{
   string result = string.Empty; 
   await Task.Run(() =>
   {
       result = PostData(apiURL, data, isNETGM);
   });
   return result;
}

It is recommended to use Task.Run for CPU-related tasks. Since CPU structures contain multiple cores, you can use Task.Run in coding that requires processor power. You can benefit from the core processing power more efficiently by opening a new thread. Task.Run is not recommended if you are performing I/O operations such as file operations and network operations. The reason for this is that there are long waits in I/O operations and this causes the processor core to fall into a waiting state for a while. In addition, care should be taken not to use Task.Run within each other unless necessary.

Let's briefly touch on Task.FromResult and Task.FromException. If there is no result to return, the process is terminated by returning Task.FromResult.

Reference :

https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

https://learn.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45#HowRequestsProcessedByTP

What is the difference between Task.Run with Task.Factory.StartNew?

Task.Run is a shortcut of Task.Factory.StartNew with default parameters.

Task.Run(A);

It is equivalent to :

Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

ConfigureAwait

In terms of ConfigureAwait, the default value is ConfigureAwait(true). Therefore, if you don’t explicitly specify it, your code will behave as if you used ConfigureAwait(true).

💡
If you see ConfigureAwait(true) in the production code, you can delete it without ill effect.

ConfigureAwait(false), I recommend using it for library code and not application code. If you don't write any library code then you probably won't ever have to use it.

You make simple use of await, and the right things happen with regards to callbacks/continuations being posted back to the original context if one existed. This leads to the general guidance:

💡
If you’re writing app-level code, do not use ConfigureAwait(false).

The setting of downloadBtn.Content = text needs to be done back in the original context.

Right usage :

private static readonly HttpClient s_httpClient = new HttpClient();
private async void downloadBtn_Click(object sender, RoutedEventArgs e)
{
    string text = await s_httpClient.GetStringAsync("http://example.com/currenttime");
    downloadBtn.Content = text;
}

Wrong usage :

private static readonly HttpClient s_httpClient = new HttpClient();
private async void downloadBtn_Click(object sender, RoutedEventArgs e)
{
    string text = await s_httpClient.GetStringAsync("http://example.com/currenttime").ConfigureAwait(false); // bug
    downloadBtn.Content = text;
}

The same would go for code in a classic ASP.NET app reliant on HttpContext.Current; using ConfigureAwait(false) and then trying to use HttpContext.Current is likely going to result in problems.

Reference :
https://devblogs.microsoft.com/dotnet/configureawait-faq/

https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html

WaitAll vs. WhenAll what's the difference:

If you have a task that does something with the UI thread (e.g. a task that represents an animation in a Storyboard) if you Task.WaitAll() then the UI thread is blocked and the UI is never updated. if you use await Task.WhenAll() then the UI thread is not blocked, and the UI will be updated.

So;

WaitAll is a blocking call

WhenAll - not - code will continue executing

Use which when:

WaitAll when cannot continue without having the result

WhenAll when what just to be notified, not blocked

References :

https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/https://stackoverflow.com/questions/38423472/what-is-the-difference-between-task-run-and-task-factory-startnewhttps://blog.stephencleary.com/2013/08/startnew-is-dangerous.html

https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f

https://stackoverflow.com/questions/51491590/an-asynchronous-operation-exceeded-the-page-timeout-trying-to-use-httprequestme

https://www.linkedin.com/pulse/should-i-use-configureawaittrue-configureawaitfalse-viswanathan/