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.


 TopicSubtopic
  Next: > Grove Beginners kit
<  Prev:   Google Home Windows Bridge
   
 This Category Links 
Category:Coding Index:Coding
<  Prev:   Nuget Packages 101