Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is async/await not working in my ASP.net 5 Console Application?

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?

like image 290
Nikon the Third Avatar asked May 28 '15 07:05

Nikon the Third


People also ask

How do you call async method from console application?

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... } }

Is async await blocking C#?

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.

How does async await C# statement work?

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.


1 Answers

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");
    }
}
like image 147
Yuval Itzchakov Avatar answered Sep 24 '22 10:09

Yuval Itzchakov