1

Here is a program that mimics the flow of my real case scenario:

using System;
using System.Threading.Tasks;

namespace TestAsync
{
    interface IInterface
    {
        Task<int> DoSomething(int i);
    }

    class MyClass : IInterface
    {
        public async void MainAsync()
        {
            var i = 1;
            Console.WriteLine("Start MainAsync:" + i);
            var t = DoSomething(i);
            Console.WriteLine("After DoSomething: " + i );
            i = await t;
            Console.WriteLine("Done waiting: " + i);
        }

        public async Task<int> DoSomething(int i)
        {
            i = i + 1;
            Console.WriteLine("In Something:" + i);
            await Task.Delay(1000);
            Console.WriteLine("After Long Process: " + i);
            return i;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var m = new MyClass();
            m.MainAsync();
            Console.WriteLine("Main done.");
        }        
    }
}

The output I am getting is this:

Start MainAsync:1
In Something:2
After DoSomething: 1
Main done.
Press any key to continue . . .

This tells me that i = await t; is popping the process back up to Main and never comes back once done with the tasks.

What am I doing wrong?

I am looking for a result like:

Start MainAsync:1
In Something:2
After DoSomething: 1
After Long Process: 2
Done waiting: 2
Main done.
Press any key to continue . . .

or maybe

Start MainAsync:1
In Something:2
After DoSomething: 1
Main done.
After Long Process: 2
Done waiting: 2
Press any key to continue . . .

Thank you for your insight.

Bibi
  • 73
  • 1
  • 5
  • 1
    I'm not seeing where the "Press any key to continue . . ." is coming from in your code. But the issue is that `async void` is fire and forget and your program is ending before the continuation from your await has a chance to even run. To fix it you could just make it `async Task` and `await` it in `Main` that would give you the first set of desired output. – juharr Apr 07 '16 at 17:04
  • An asynchronous application needs one blocking function so the program doesn't exit (or continue). A form project has a blocking function built into the class. A Console application doesn't have a blocking function. The easiest way of creating a block is in main have a continuous while loop : while(1){your code here}; This way the code waits for the async code to finish without terminating the application. – jdweng Apr 07 '16 at 17:28
  • I like using awaitone for a block. See following webpage : https://msdn.microsoft.com/en-us/library/58195swd(v=vs.110).aspx – jdweng Apr 07 '16 at 17:37
  • 1
    @juharr In visual studio pressing Ctrl-F5 instead of F5 will stop the program at completion and add the line "Press any key to continue..." – Bibi Apr 07 '16 at 18:13

1 Answers1

6

Once the main method has completed you now no longer have any non-background threads running in your program, so the whole process will end. The fact that you have code that is going to eventually fire at some point in the future doesn't change that.

This is why you would normally have a message loop at the top level of your application, able to accept and process messages, and wait for more messages if there are currently none to process. Since the thread that is running the message pump would be a non-background thread, it wouldn't allow the process to end until the whole loop is closed.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    Nice explanation, for solution (and more historical details) - http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app – Alexei Levenkov Apr 07 '16 at 17:09
  • Following the article suggested by @AlexeiLevenkov I have modified Main with `Task.Run(() => m.MainAsync()).Wait();` and got the expected results. Thank you @Servy for the explanation. – Bibi Apr 07 '16 at 18:10