How to Call an Async Method in Main

How can I call an async method in Main?

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.

Calling an async function from main in C#

 Task.Run(async () => { await d.DownloadFilesAsync();}).Wait();

C#: call async method inside Main of console application leads to compilation failure

Your Main method doesn't comply with one of the valid signatures listed here.

You probably want to use this:

public static async Task Main(string[] args)

A Task needs to be returned, so that the runtime knows when the method is complete; this couldn't be determined with void.

The compiler achieves this by generating a synthetic entry point:

private static void $GeneratedMain(string[] args) => 
Main(args).GetAwaiter().GetResult();

Can't specify the 'async' modifier on the 'Main' method of a console app

As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP.

Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this:

class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}

The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption.


I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post:

If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable.

Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context).

Here's why this is a problem in Console programs with an async Main:

Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits.

One solution is to provide your own context - a "main loop" for your console program that is async-compatible.

If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My Documents\Microsoft Visual Studio Async CTP\Samples(C# Testing) Unit Testing\AsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package.

Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage:

using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}

static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}

Alternatively, you can just block the main Console thread until your asynchronous work has completed:

class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}

static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}

Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.

C# Async method call all the way to Main

below is a full example. you can run the ReserverAHoliday both Synchronously (bool r = ReserveAHolliday().Result;) and Asynchronously (just call ReserveAHolliday();) from MAIN (depends which line you comment). and you can see the effect ("END" gets printed before / after the reservation is complete).
I prefer the await Task.WhenAll() methods, which is more readable.
also note that it's preferred to use await Task.Delay(100) instead of Thread.sleep inside GetNumber1.

    class Program
{
static void Main(string[] args)//main cant' be async
{
//int res = test().Result;//I must put await here
bool r = ReserveAHolliday().Result; //this will run Synchronously.
//ReserveAHolliday(); //this option will run aync : you will see "END" printed before the reservation is complete.
Console.WriteLine("END");
Console.ReadLine();
}

public async static Task<int> test()
{ //why can't I make it just: public int test()??
//becuase you cannot use await in synchronous methods.
int a1, a2, a3, a4;

a1 = await GetNumber1();
a2 = await GetNumber1();
a3 = await GetNumber1();

a4 = a1 + a2 + a3;
return a4;
}

public static async Task<int> GetNumber1()
{
//await Task.Run(() =>
// {
for (int i = 0; i < 10; i++)
{
Console.WriteLine("GetNumber1");
await Task.Delay(100); // from what I read using Task.Delay is preferred to using System.Threading.Thread.Sleep(100);
}
// });
return 1;
}

public async static Task<bool> ReserveAHolliday()
{
//bool hotelOK = await ReserveAHotel();//HTTP async request
//bool flightOK = await ReserveAHotel();////HTTP async request
var t1 = ReserveAHotel("FirstHotel");
var t2 = ReserveAHotel("SecondHotel");
await Task.WhenAll(t1, t2);
bool result = t1.Result && t1.Result;// hotelOK && flightOK;
return result;
}
public static async Task<bool> ReserveAHotel(string name)
{
Console.WriteLine("Reserve A Hotel started for "+ name);
await Task.Delay(3000);
if (name == "FirstHotel")
await Task.Delay(500); //delaying first hotel on purpose.
Console.WriteLine("Reserve A Hotel done for " + name);
return true;
}
}

call async function in main function

In Python 3.7+ you can just use asyncio.run(coroutine())

In earlier versions you have to get the event loop and run from there:

loop = asyncio.get_event_loop()
asyncio.ensure_future(coroutine())
loop.run_forever()
loop.close()

The correct way to invoke an async function main?

The use of then together with async..await isn't necessary because it's syntactic sugar for then.

Entry point could be async IIFE (IIAFE):

(async () => {
try {
var conn = await mysql.createConnection(config.mysql);
...
var [response] = await conn.execute(`
SELECT something
FROM some_table
WHERE field = ?
`, [value]);
...
process.exit(0);
} catch (err) {
console.error(err);
process.exit(1);
}
})();

There also may be no need for process.exit(0) if the connection was closed.

Why does conn.execute() return an error (which I need to manually check) rather than throwing one?

It doesn't, and isn't conventional for promise-enabled functions to return an error in a result.

Callback-based execute uses error-first callback for errors. Promise-based execute can't throw an error because it returns a promise which is rejected in case of error.

As the documentation shows, the second element is fields and not error:

const [rows, fields] = await conn.execute('select ?+? as sum', [2, 2]);

It may return rejected promise which can be caught with try..catch inside async function in case of error.

How to call an async function?

according to async_function MDN

Return value

A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.

async function will always return a promise and you have to use .then() or await to access its value

async function getHtml() {
const request = await $.get('https://jsonplaceholder.typicode.com/posts/1')
return request
}

getHtml()
.then((data) => { console.log('1')})
.then(() => { console.log('2')});

// OR

(async() => {
console.log('1')
await getHtml()
console.log('2')
})()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to call a async task from main()

The simplest thing to do is to block the call and wait. You're not getting async behavior, but hey - you're in a console app on a single thread anyway.

call().Wait();

If instead you want true async behavior, including a message pump and synchronization context, (perhaps because you have other things going on in your console app simultaneously), you have a few different options:

  1. Use the AsyncPump class from Stephen Toub's MSDN post.

  2. Use the AsyncContext class from Stephen Cleary's AsyncEx project.

  3. If you're using the new .NET Core (aka "DNX"), then you can just make your Main method async, as in:

    static async Task Main(string[] args)


Related Topics



Leave a reply



Submit