124
public class test
{
    public async Task Go()
    {
        await PrintAnswerToLife();
        Console.WriteLine("done");
    }

    public async Task PrintAnswerToLife()
    {
        int answer = await GetAnswerToLife();
        Console.WriteLine(answer);
    }

    public async Task<int> GetAnswerToLife()
    {
        await Task.Delay(5000);
        int answer = 21 * 2;
        return answer;
    }
}

if I want to call Go in main() method, how can I do that? I am trying out c# new features, I know i can hook the async method to a event and by triggering that event, async method can be called.

But what if I want to call it directly in main method? How can i do that?

I did something like

class Program
{
    static void Main(string[] args)
    {
        test t = new test();
        t.Go().GetAwaiter().OnCompleted(() =>
        {
            Console.WriteLine("finished");
        });
        Console.ReadKey();
    }


}

But seems it's a dead lock and nothing is printed on the screen.

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
Larry
  • 2,172
  • 2
  • 14
  • 20
  • seems I found the problem, cos GetAwaiter().OnCompleted() will return to main function immediately, so when Console.Readkey() is called, the main thread is blocking therefore the output message returned from task can not be printed to the screen cos it's waiting for the main thread to unblock. If I replace Console.readkey() with while (true) { Thread.Sleep(1000); } it works fine. – Larry Oct 21 '12 at 22:26

9 Answers9

152

Your Main method can be simplified. For C# 7.1 and newer:

static async Task Main(string[] args)
{
    test t = new test();
    await t.Go();
    Console.WriteLine("finished");
    Console.ReadKey();
}

For earlier versions of C#:

static void Main(string[] args)
{
    test t = new test();
    t.Go().Wait();
    Console.WriteLine("finished");
    Console.ReadKey();
}

This is part of the beauty of the async keyword (and related functionality): the use and confusing nature of callbacks is greatly reduced or eliminated.

Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • @MarcGravell I have incorporated the new approach into my answer. DavidG's answer gives a bit more detail, but I'm no longer out of date. – Tim S. May 10 '18 at 16:02
  • You may need to modify your project file to allow for the use of c# 7.0 and above. Answer posted [here](https://stackoverflow.com/a/47588563/1254187) – Luke Feb 24 '20 at 11:10
  • 1
    Is it not better to use `t.Go().GetAwaiter().GetResult()` for earlier versions of C#, so that an exception is not wrapped in `AggregateException`? And is it not possible the option for earlier versions of C# results in deadlock? – Code Pope Jul 02 '21 at 09:50
30

Instead of Wait, you're better off using new test().Go().GetAwaiter().GetResult() since this will avoid exceptions being wrapped into AggregateExceptions, so you can just surround your Go() method with a try catch(Exception ex) block as usual.

arviman
  • 5,087
  • 41
  • 48
  • @MarkAlicz [Unless you are using C# 7.1 or newer of course.](https://stackoverflow.com/a/45368969/1663001) – DavidG May 10 '18 at 15:57
  • Do not call GetResult() on an async method. This will block the main thread. This not only defeats the purpose of asynchronous methods, but also leave the room for deadlocks. – Ruchira Sep 27 '19 at 00:15
  • 2
    @Ruchira, the same can happen with `Wait`. So how should the problem been solved when you don't have C# 7.1 or newer where the `main` function can be declared as `async`? – Code Pope Jul 02 '21 at 09:46
29

Since the release of C# v7.1 async main methods have become available to use which avoids the need for the workarounds in the answers already posted. The following signatures have been added:

public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);

This allows you to write your code like this:

static async Task Main(string[] args)
{
    await DoSomethingAsync();
}

static async Task DoSomethingAsync()
{
    //...
}
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • 2
    I am trying with `static async Task Main(string[] args)`, but I get the error `CS5001 Program does not contain a static 'Main' method suitable for an entry point`. I have checked project properties and there is no startup object available in the dropdown. Using the latest update of VS2017 + .NET Core 2.0. How do I overcome this? – NightOwl888 Apr 12 '18 at 09:33
  • @NightOwl888 Can you see C# 7.1 in the project properties? – DavidG Apr 12 '18 at 09:41
  • 5
    Yes I can, thank you. The default setting is "latest major version", so it was defaulting to 7.0. I changed to 7.1 and it compiles now. – NightOwl888 Apr 12 '18 at 09:44
15
class Program
{
    static void Main(string[] args)
    {
       test t = new test();
       Task.Run(async () => await t.Go());
    }
}
maxspan
  • 13,326
  • 15
  • 75
  • 104
  • 3
    This answer creates a background thread which can cause problems if the foreground thread completes first – Luke Feb 24 '20 at 11:11
14

As long as you are accessing the result object from the returned task, there is no need to use GetAwaiter at all (Only in case you are accessing the result).

static async Task<String> sayHelloAsync(){

       await Task.Delay(1000);
       return "hello world";

}

static void main(string[] args){

      var data = sayHelloAsync();
      //implicitly waits for the result and makes synchronous call. 
      //no need for Console.ReadKey()
      Console.Write(data.Result);
      //synchronous call .. same as previous one
      Console.Write(sayHelloAsync().GetAwaiter().GetResult());

}

if you want to wait for a task to be done and do some further processing:

sayHelloAsyn().GetAwaiter().OnCompleted(() => {
   Console.Write("done" );
});
Console.ReadLine();

If you are interested in getting the results from sayHelloAsync and do further processing on it:

sayHelloAsync().ContinueWith(prev => {
   //prev.Result should have "hello world"
   Console.Write("done do further processing here .. here is the result from sayHelloAsync" + prev.Result);
});
Console.ReadLine();

One last simple way to wait for function:

static void main(string[] args){
  sayHelloAsync().Wait();
  Console.Read();
}

static async Task sayHelloAsync(){          
  await Task.Delay(1000);
  Console.Write( "hello world");

}
Muhammad Soliman
  • 21,644
  • 6
  • 109
  • 75
5
public static void Main(string[] args)
{
    var t = new test();
    Task.Run(async () => { await t.Go();}).Wait();
}
roottraveller
  • 7,942
  • 7
  • 60
  • 65
Sami Hussain
  • 179
  • 3
  • 9
3

Use .Wait()

static void Main(string[] args){
   SomeTaskManager someTaskManager  = new SomeTaskManager();
   Task<List<String>> task = Task.Run(() => marginaleNotesGenerationTask.Execute());
   task.Wait();
   List<String> r = task.Result;
} 

public class SomeTaskManager
{
    public async Task<List<String>> Execute() {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri("http://localhost:4000/");     
        client.DefaultRequestHeaders.Accept.Clear();           
        HttpContent httpContent = new StringContent(jsonEnvellope, Encoding.UTF8, "application/json");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        HttpResponseMessage httpResponse = await client.PostAsync("", httpContent);
        if (httpResponse.Content != null)
        {
            string responseContent = await httpResponse.Content.ReadAsStringAsync();
            dynamic answer = JsonConvert.DeserializeObject(responseContent);
            summaries = answer[0].ToObject<List<String>>();
        }
    } 
}
Jean-Philippe
  • 397
  • 4
  • 5
1

C# 9 Top-level statements simplified things even more, now you don't even have to do anything extra to call async methods from your Main, you can just do this:

using System;
using System.Threading.Tasks;

await Task.Delay(1000);
Console.WriteLine("Hello World!");

For more information see What's new in C# 9.0, Top-level statements:

The top-level statements may contain async expressions. In that case, the synthesized entry point returns a Task, or Task<int>.

Stan Prokop
  • 5,579
  • 3
  • 25
  • 29
0

try "Result" property

class Program
{
    static void Main(string[] args)
    {
        test t = new test();
        t.Go().Result;
        Console.ReadKey();
    }
}
Chitta
  • 206
  • 2
  • 6