When a new ASP.NET Core 2.0 project is created, the boilerplate Main
method in the Program
class looks something like this:
public static void Main(string[] args) { BuildWebHost(args).Run(); // BuildWebHost returns an IWebHost }
But since C# 7.1, the Main
method can be an asynchronous method returning Task
instead of void
. This means it's much easier to call an async method inside Main
.
So the RunAsync()
on IWebHost
can be called inside Main
instead of the Run()
method. Something like this:
public static async Task Main(string[] args) { await BuildWebHost(args).RunAsync().ConfigureAwait(false); }
According to the documentation, the Run
method:
Runs a web application and block the calling thread until host shutdown.
Whereas the RunAsync
method:
Runs a web application and returns a Task that only completes when the token is triggered or shutdown is triggered.
I was wondering when should the RunAsync
method be used instead of the regular Run
method? What are the practical implications of this? Would the end-user notice any difference?
The IWebHost is the core of your ASP.NET Core application, containing the application configuration and the Kestrel server that listens for requests and sends responses.
The default ASP.NET Core templates contain the following Main
method:
public static void Main(string[] args) { BuildWebHost(args).Run(); }
That Run
method there is the WebHostExtensions.Run
extension method which is implemented like this:
public static void Run(this IWebHost host) { host.RunAsync().GetAwaiter().GetResult(); }
So this actually calls WebHostExtensions.RunAsync
, and just blocks on it.
Now, let’s look at how C# 7.1’s asynchronous Main
method is specified:
When one of [these task-based methods] is identified as the entrypoint, the compiler will synthesize an actual entrypoint method that calls one of these coded methods:
static Task Main()
will result in the compiler emitting the equivalent ofprivate static void $GeneratedMain() => Main().GetAwaiter().GetResult();
static Task Main(string[])
will result in the compiler emitting the equivalent ofprivate static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();
So basically, having an asynchronous Main
method like this:
public static async Task Main(string[] args) { await BuildWebHost(args).RunAsync(); }
Will cause the compiler to also emit the following:
private static void $GeneratedMain(string[] args) { Main(args).GetAwaiter().GetResult(); }
And if you look close at what happens with the returned task there, this is pretty much the exact same thing as what the WebHostExtensions.Run
method does.
So what does this mean? You can use either of these solutions and the effect will be the same. Your application will properly block until the asynchronous task gets resolved. There is no practical difference between the solutions. The only real benefit you would have from using an asynchronous main method would be if you had other asynchronous work to do in the Main
method; although this would likely be very rare case since for web applications, you are more likely to do setup work within the lifecycle of the ASP.NET Core application (i.e. in Startup
, and not outside of it).
What are the practical implications of this? Would the end-user notice any difference?
There is no difference on RunTime level behavior.
Since this feature does not correspond to a CLR code change, the async Main method is just a syntactical sugar. This design allows backend compatibility with the previous versions of the language. To read more details, please see Async Main in the Roslyn Git repo.
- C# 7 Series, Part 2: Async Main
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With