Studying keywords await and async (ASP.NET C#)
To do a study about task based asynchronous calls in .NET 4.5 we are going to use a C# console application.
A single limitation: The main method, the entry point of the console application, can't be async. It's a .NET rule, not mine.
Please import System.Net and System.Threading.Tasks namespaces.
Please import System.Net and System.Threading.Tasks namespaces.
Case 1- Caller is not async and function called is async
Code:
static void Main(string[] args)
{
Console.WriteLine("Main Begin");
var t = DownloadAsync();
Console.WriteLine("Main End");
Console.ReadKey();
}
static async Task DownloadAsync()
{
Console.WriteLine("DownloadAsync Begin");
using (var web = new System.Net.WebClient())
Console.WriteLine((await web.DownloadStringTaskAsync("http://www.google.com/")).Substring(0, 50));
Console.WriteLine("DownloadAsync End");
}
Main Begin
DownloadAsync Begin
Main End
<!doctype html><html itemscope="" itemtype="http:/
DownloadAsync End
As you can see, the function runs asynchronously, Main method ends first, because of http comunication. Let's use the wait method of Task, so the Main method waits for DownloadAsync.
Code:
static void Main(string[] args)
{
Console.WriteLine("Main Begin");
var t = DownloadAsync();
Console.WriteLine("Calling Wait Method of Task");
t.Wait();
Console.WriteLine("Main End");
Console.ReadKey();
}
{
Console.WriteLine("Main Begin");
var t = DownloadAsync();
Console.WriteLine("Calling Wait Method of Task");
t.Wait();
Console.WriteLine("Main End");
Console.ReadKey();
}
Output:
Main Begin
DownloadAsync Begin
Calling Wait Method of Task
<!doctype html><html itemscope="" itemtype="http:/
DownloadAsync End
Main End
The wait method of the Task, makes the Main method wait the asynchronous task to end.
Case 2- Caller is async and function called is async
Code:
static void Main(string[] args)
{
var t = MainAsync();
Console.ReadKey();
}
static async Task MainAsync()
{
Console.WriteLine("Main Begin");
var t = DownloadAsync();
Console.WriteLine("Using wait operator");
await t;
Console.WriteLine("Main End");
}
static async Task DownloadAsync()
{
Console.WriteLine("DownloadAsync Begin");
using (var web = new System.Net.WebClient())
Console.WriteLine((await web.DownloadStringTaskAsync("http://www.google.com/")).Substring(0, 50));
Console.WriteLine("DownloadAsync End");
}
static void Main(string[] args)
{
var t = MainAsync();
Console.ReadKey();
}
static async Task MainAsync()
{
Console.WriteLine("Main Begin");
var t = DownloadAsync();
Console.WriteLine("Using wait operator");
await t;
Console.WriteLine("Main End");
}
static async Task DownloadAsync()
{
Console.WriteLine("DownloadAsync Begin");
using (var web = new System.Net.WebClient())
Console.WriteLine((await web.DownloadStringTaskAsync("http://www.google.com/")).Substring(0, 50));
Console.WriteLine("DownloadAsync End");
}
Output:
Main Begin
DownloadAsync Begin
Using wait operator
<!doctype html><html itemscope="" itemtype="http:/
DownloadAsync End
Main End
We achieve the same result! The difference is that with async methods instead of using the Wait() method of Task we use the await operator, a .NET sugar to use instead of Wait() method. If your code is very simple and doesn't need to control if Asynchronous call is processing indefinitely, you can use the wait operator. If you need to control the time that async function will take, or some other kind of control, then you can do it using Task Methods.
Case 3- Caller is async and function called is not async
Code:
static void Main(string[] args)
{
var t = MainAsync();
Console.ReadKey();
}
static async Task MainAsync()
{
Console.WriteLine("Main Begin");
Download();
Console.WriteLine("Main End");
}
static void Download()
{
Console.WriteLine("Download Begin");
using (var web = new System.Net.WebClient())
Console.WriteLine((web.DownloadStringTaskAsync("http://www.google.com/")).Result.Substring(0, 50));
Console.WriteLine("Download End");
}
Output:
Main Begin
Download Begin
<!doctype html><html itemscope="" itemtype="http:/
Download End
Main End
By the results we can see that the code runs synchronously. If the function we are calling is sync it will run sync by default. But we can still make an asynchronous call, using Task.Run(), as we'll see in the next situation.
Case 4- Caller is not async and function called is not async
In this case all code execute in the sequence that is given, in one word, synchronously.
But we can still make an asynchronous call, using Task.Run().
Code:
static void Main(string[] args)
{
Console.WriteLine("Main Begin");
var t = Task.Run(() => Download());
Console.WriteLine("Main End");
Console.ReadKey();
}
static void Download()
{
Console.WriteLine("Download Begin");
using (var web = new System.Net.WebClient())
Console.WriteLine((web.DownloadStringTaskAsync("http://www.google.com/")).Result.Substring(0, 50));
Console.WriteLine("Download End");
}
Output:
Main Begin
Main End
Download Begin
<!doctype html><html itemscope="" itemtype="http:/
Download End
Task.Run is not perfect substitute for async methods, but it worked. Lets give some time to the task so it can at least start:
static void Main(string[] args)
{
Console.WriteLine("Main Begin");
var t = Task.Run(() => Download());
t.Wait(10);
Console.WriteLine("Main End");
Console.ReadKey();
}
{
Console.WriteLine("Main Begin");
var t = Task.Run(() => Download());
t.Wait(10);
Console.WriteLine("Main End");
Console.ReadKey();
}
Output:
Main Begin
Download Begin
Main End
<!doctype html><html itemscope="" itemtype="http:/
Download End
This the function started before Main ended, and continued asynchronously after it ended. But we can still use the Wait method without parameters (equals to wait indefinitely):
static void Main(string[] args)
{
Console.WriteLine("Main Begin");
var t = Task.Run(() => Download());
t.Wait();
Console.WriteLine("Main End");
Console.ReadKey();
}
Output:
Main Begin
Download Begin
<!doctype html><html itemscope="" itemtype="http:/
Download End
Main End
And the async call executed in propper order.
Conclusion:
Although .NET let you relly on Task.Run to start async calls, prefer using await and async operators, or at least async operator and Task methods to control the Asynchronous method invoked.