I tried this simple ASP.net 5 Console Application on both Windows (.NET 4.5.1) and Linux (Mono 4.0.1), both times with the same result.
Note: I called it an ASP.net 5 Console Application because that is what is was called in Visual Studio up to RC. Now it is called Console Application (Package), but it still uses DNX from https://github.com/aspnet/dnx :)
My Program.cs
:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
public class Program
{
public async void Main(String[] args)
{
#if DNX451
AppDomain.CurrentDomain.UnhandledException +=
(s, e) => Console.WriteLine(e);
#endif
try
{
await Task.Delay(1000);
Console.WriteLine("After Task.Delay");
}
finally
{
Console.WriteLine("Inside Finally");
}
}
}
}
My project.json
:
{
"version": "1.0.0-*",
"dependencies": {},
"commands": {
"ConsoleApplication": "ConsoleApplication"
},
"frameworks": {
"dnx451": {}
}
}
When running with either 1.0.0-beta4 CLR
or 1.0.0-beta5-11904 CLR
, the command dnx . ConsoleApplication
prints nothing. The program exits with status code 0 as soon as it encounters the Task.Delay
. Even the finally block is never executed.
I couldn't test .NET Core 5.0 because dnu restore
says everything is OK, but the packages can't be located by the runtime. Oh well...
Does anybody have the same problems with async/await and DNX? Or spot some error I made?
An easy fix is to move the async code block into a separate method that you can mark with async and call from Main : class Program { static void Main(string[] args) { // Call SomeAsyncCode() somehow } private static async Task SomeAsyncCode() { // Use await here! await Task. Delay(10); // Other async goodness... } }
The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.
The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.
If you see my question (and answer) in Entry point can be marked with the 'async' modifier on CoreCLR?, you'll see that at the top-most of the call-stack, you have the following:
public static int Execute(string[] args)
{
// If we're a console host then print exceptions to stderr
var printExceptionsToStdError = Environment
.GetEnvironmentVariable
(EnvironmentNames.ConsoleHost) == "1";
try
{
return ExecuteAsync(args).GetAwaiter().GetResult();
}
catch (Exception ex)
{
if (printExceptionsToStdError)
{
PrintErrors(ex);
return 1;
}
throw;
}
}
Internally, it checks to see the return type of the method, if the return type is of type Task
, then it registers a ContinueWith
, which it'll be able to synchronously wait on:
if (result is Task)
{
return ((Task)result).ContinueWith(t =>
{
return 0;
});
}
When you pass in async void
, it looks to Execute
as if this method is a "fire and forget" void returning method. That's why it never finishes execution. But, if you change it to return a Task
, it'll work:
public async Task Main(String[] args)
{
#if DNX451
AppDomain.CurrentDomain.UnhandledException +=
(s, e) => Console.WriteLine(e);
#endif
try
{
await Task.Delay(1000);
Console.WriteLine("After Task.Delay");
}
finally
{
Console.WriteLine("Inside Finally");
}
}
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