Can't Specify the 'Async' Modifier on the 'Main' Method of a Console App

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#: 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();

Cannot create an async Main

Your visual studio by default will be setted to this
Sample Image
Which means that the major version will be 7.0 and not 7.1 you should force it to 7.1 in order to compile it with the 7.1 version

The second option in Project Properties=> Build =>advanced set the language version to C# latest minor version(latest)

Using 'async' in a console application in C#

In most project types, your async "up" and "down" will end at an async void event handler or returning a Task to your framework.

However, Console apps do not support this.

You can either just do a Wait on the returned task:

static void Main()
{
MainAsync().Wait();
// or, if you want to avoid exceptions being wrapped into AggregateException:
// MainAsync().GetAwaiter().GetResult();
}

static async Task MainAsync()
{
...
}

or you can use your own context like the one I wrote:

static void Main()
{
AsyncContext.Run(() => MainAsync());
}

static async Task MainAsync()
{
...
}

More information for async Console apps is on my blog.

An entry point cannot be marked with the 'async' modifier

The error message is exactly right: the Main() method cannot be async, because when Main() returns, the application usually ends.

If you want to make a console application that uses async, a simple solution is to create an async version of Main() and synchronously Wait() on that from the real Main():

static void Main()
{
MainAsync().Wait();
}

static async Task MainAsync()
{
// your async code here
}

This is one of the rare cases where mixing await and Wait() is a good idea, you shouldn't usually do that.

Update: Async Main is supported in C# 7.1.

C# - Use Async in Main function

async Task Main is available in C# 7.1. You can change it in build properties (the default is the latest major version, which is 7.0)

Asynchronous method does not work well in Console application

Your program finishes before the Wait and terminates (including the "wait" method). You need to await the task returned by Delay somewhere. To have desired output you can do it like that, for example (using C# 7.1 async Main feature):

class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("*** Main Method Start ***");
var t = Operation();
Console.WriteLine("*** Main Method End ***");
await t;
}
static Task Operation()
{
Console.WriteLine("*** Operation Method Start ***");
var task1 = Delay(5000);
Console.WriteLine("*** Operation Method End ***");
return task1 ;
}

static async Task<int> Delay(int ms)
{
Console.WriteLine($"Start {ms}(ms) Delay");
await Task.Delay(ms);
Console.WriteLine($"End {ms}(ms) Delay");
return ms;
}
}


Related Topics



Leave a reply



Submit