Although it's becoming less and less common, there are times you will need to call an asynchronous from within a synchronous one. For example when you are implementing an interface; within a constructor or writing a console application with an old version of c#.
Create a console app, and start with the following code
```c# static void Main(string[] args) { if (File.Exists("Log.txt")) File.Delete("Log.txt"); File.AppendAllText("Log.txt", "Main 1\r\n"); AnAsyncOperation(); File.AppendAllText("Log.txt", "Main 2\r\n");
Console.WriteLine("Wait a couple of seconds and then press a key");
Console.ReadKey(true);
}
public static async Task AnAsyncOperation() { await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(1))); File.AppendAllText("Log.txt", "AnAsyncOperation\r\n"); } ```
Run the program, and within your bin/debug folder the file log.txt will be created. This file should contain the following three lines, note the lines are out of order.
Main 1
Main 2
AnOperationAsync
Now remove the Console.ReadKey(true) line and run the program again. Now your log file will contain just two lines
Main 1
Main 2
As you may have guessed, the reason for this is that AnAsyncOperation is an asynchronous method, and we aren't awaiting for it to finish. Our program is exiting before the 1 second delay has finished.
Ideally we would change our code as below
c#
await AnAsyncOperation();
but we can't as we haven't marked our method as async. static async Task Main(string[] args)
(Let's assume we are using an old version of c# for now!)
You may be tempted to use the .Wait() command, change your program as below and run it again.
c#
AnAsyncOperation().Wait();
As first it appears to correct the problem, the log file now contains all three lines and they are in the correct order. However now change your code to read
```c# static void Main(string[] args) { if (File.Exists("Log.txt")) File.Delete("Log.txt"); File.AppendAllText("Log.txt", "Main 1\r\n");
try
{
AnAsyncOperation().Wait();
}
catch (ApplicationException)
{
// That's ok
}
File.AppendAllText("Log.txt", "Main 2\r\n");
}
public static async Task AnAsyncOperation() { throw new ApplicationException("Please bring the warp drive online before calling this method."); } ```
Before running it, guess what you think is going to happen.
Now run it, you will find that the ApplicationException isn't caught, and the program crashes leaving just one line in the log.txt file. The problem is that thrown exception is actually of type System.AggregateException containing our ApplicationException as an inner exception. Normally this isn't a problem as the await keyword also handles the unwrapping of our exception for us.
The answer is to use GetAwaiter().GetResult() instead of .Wait() or .Result. i.e.
c#
try
{
AnAsyncOperation().GetAwaiter().GetResult();
}
Run the program, and you will now find that your exception is correctly caught.
There are three rules for when you need to call an asynchronous method.
There is a minor exception to these rules which we will look at next time.
#1 As @kev_bite pointed out to me, there are very few reasons not to make your method asynchronous in modern C#. For example C# 7.1 supports asynchronous Main methods in console apps, and you can use IHttpAsyncHandler instead of IHttpHandler in asp.net.
Correcting Common Mistakes When Using Async/Await in .NET - Brandon Minnick