Dave
Dave

Reputation: 2601

Why can't I debug code in an async method?

I actually started the night trying to learn more about MongoDB, but am getting hung up and the .NET await/async stuff. I am trying to implement the code shown on MongoDB's site. I've had to modify it a tad bit, so I could get my program to compile. I now have the following in my console application:

protected static IMongoClient _client;
protected static IMongoDatabase _database;

static void Main(string[] args)
{
    _client = new MongoClient();
    _database = _client.GetDatabase("test");

    GetDataAsync();
}

private static async void GetDataAsync() //method added by me.
{
    int x = await GetData();
}

private static async Task<int> GetData()
{
    var collection = _database.GetCollection<BsonDocument>("restaurants");
    var filter = new BsonDocument();
    var count = 0;
    Func<int> task = () => count; //added by me.
    var result = new Task<int>(task); //added by me.
    using (var cursor = await collection.FindAsync(filter)) //Debugger immediately exits here, goes back to main() and then terminates. 
    {
        while (await cursor.MoveNextAsync())
        {
            var batch = cursor.Current;
            foreach (var document in batch)
            {
                // process document
                count++;
            }
        }
    }

    return count; //added by me
}

When I run the application, the debugger will call into my GetDataAsync() method which in turn calls into the GetData() method. It gets to the line using (var cursor = await collection.FindAsync(filter)) and then immediately returns to finish the main() method.

Any break points I put below that line are ignored, as are any breakpoints I put in the GetDataAsync() method. Is this code just not getting run because the program exits? Can someone explain to me what is going on?

Upvotes: 51

Views: 68791

Answers (3)

Harshil Parekh
Harshil Parekh

Reputation: 166

You can use Result property of async method.

static void Main(string[] args)
{
    int x = GetData().Result;  

    // Result property will return you the out put datatype (not Task<datatype>)
    // Thread will be blocked here, to get you the data
}

private static async Task<int> GetData()
{
    // your code to get integer value return.

    return count;
}

Upvotes: 0

Luke
Luke

Reputation: 855

I' not so good with async dev and had a similar problem, however I was kicking off the async method in Main like:

Task.Run(async () => await GetDataAsync());

I think the Garbage Collector was disposing of the anonymous method as nothing had a reference to it anymore. Using Fabien's .Wait() allowed me to step through the program and debug. I am using netcore 2.1 with vs2017

Upvotes: 6

Fabien ESCOFFIER
Fabien ESCOFFIER

Reputation: 4911

Because you are not awaiting your GetDataAsync method. When the first await is reached the thread is returned to the caller. Since you are not waiting for the completion of the task, your console application exits and your breakpoint is not reached. You will also need to update the GetDataAsync method to return a Task rather than void. You cannot await void. You should avoid using async void for anything other than the event handler.

protected static IMongoClient _client;
protected static IMongoDatabase _database;

static void Main(string[] args)
{
    _client = new MongoClient();
    _database = _client.GetDatabase("test");

    GetDataAsync().Wait(); 
    // Will block the calling thread but you don't have any other solution in a console application
}

private static async Task GetDataAsync() //method added by me.
{
    int x = await GetData();
}

private static async Task<int> GetData()
{
    var collection = _database.GetCollection<BsonDocument>("restaurants");
    var filter = new BsonDocument();
    var count = 0;
    Func<int> task = () => count; //added by me.
    var result = new Task<int>(task); //added by me.
    using (var cursor = await collection.FindAsync(filter)) //Debugger immediately exits here, goes back to main() and then terminates. 
    {
        while (await cursor.MoveNextAsync())
        {
            var batch = cursor.Current;
            foreach (var document in batch)
            {
                // process document
                count++;
            }
        }
    }

    return count; //added by me
}

Upvotes: 53

Related Questions