C# Async Threading in Console Apps
With a Console app that has async methods, it’s important to not have a situation where the app completes before these async threads complete. A sorry tail of what not to do!
Scenario
Was reusing and extending a previous (2 or more years ago) C# Console app for sending telemetry to an Azure IoT Hub. I refactored this into a single method in a class library and then published it on GitHub. I found one version of another Console app built to use the Nuget package that was supposed to loop with a delay and send new telemetry after each delay. One version of it worked OK and another fell out after one sensor read. The code was on a remote device so I spent some time tring to solve this before I exported it back to my desktop and did a full comparison. Turned out that the version that worked had Console.ReadLine();
at the end of the Main method whereas the other had Console.WriteLine("done);
.
Initial catch all
Put try .. catches throughout the code expecting an error to be trapped somewhere. Didn’t help. Seemed that an error was causing code to jump back to teh end of Main() ???. But alas I was fooled for awhile …
Analysis
Turned out there was a an invalid mix of async coding. The Console app was calling into methods 4 deep from the apps main() method which wasn’t async. So the Console.ReadLine() was letting the async method/s run to completion whereas the Console.WriteLine() wasn’t.
Things to avoid
Don’t use .GetAwaiter
applied to a an async method within a method that is is not an async task.
For exmaple with an async method such as :
async Task DoSomethingAsync()
...{
}
Would normally call it using it:
await DoSomethingAsync();
But the calling must come from an async method.
But if calling from a void nonasync method the trick was:
DoSomethingAsync().GetAwaiter();
Also don’t use async void
methods.
Solution
The main problem was that prior to C# 7.1 the Main() in a Console app could only be of type void or int. You now can have a Main() that is of type Task
or Task<int>
. This means you don’t need to use
.GetAwaiter()
to fudge things with void mains() when calling async methods from there. 😀
class Program
{
static async Task Main(string[] args)
{
instead of
class Program
{
static void Main(string[] args)
{
Finally Check through the app that all async Task methods are called by async Tasks.
Topic | Subtopic | |
Next: > | Grove Beginners kit | Arduino Lesson 1a Flashing LED |
< Prev: | Google Home Windows Bridge | To Azure IoTHub |
This Category Links | ||
Category: | Coding Index: | Coding |
Next: > | Monkeys on a typewriter coding | |
< Prev: | Nuget Packages 101 | Including a README |