为什么我无法在异步方法中调试代码?

50

我实际上在尝试学习更多关于MongoDB的知识,但在.NET的await/async方面遇到了一些问题。我正试图实现MongoDB官网 上的代码,但需要稍作修改以便程序能够编译通过。我现在在我的控制台应用程序中有以下内容:

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
}
当我运行应用程序时,调试器会调用我的GetDataAsync()方法,该方法反过来又调用GetData()方法。它到达using (var cursor = await collection.FindAsync(filter))这一行,然后立即返回以完成main()方法。
此行以下的任何断点都将被忽略,以及我放置在GetDataAsync()方法中的任何断点。这段代码是否因程序退出而未运行?有人能解释一下发生了什么吗?

在 Visual Studio 更新后,处理调试模式变得更加一致。如果您还没有更新,建议尽快更新。希望这篇文章能够帮到您:https://devblogs.microsoft.com/visualstudio/how-do-i-debug-async-code-in-visual-studio/ - Serhat MERCAN
3个回答

52

因为您没有等待 GetDataAsync 方法。当第一个 await 到达时,线程将返回给调用者。由于您没有等待任务完成,您的控制台应用程序退出并且未达到断点。您还需要更新 GetDataAsync 方法以返回 Task 而不是void。您不能等待空值。您应该避免使用异步void除了事件处理程序之外的任何其他内容。

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
}

1
我尝试过了,但最终出现了编译错误:“运算符'.'不能应用于类型为'void'的操作数”。 - Dave
1
为什么断点从未被触发的优秀描述。 - webworm
C#的Web应用程序出现了死锁。 - Amay Kulkarni

6

我对异步开发并不是很熟练,曾经遇到过类似的问题。然而,我在 Main 中启动异步方法的方式如下:

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

我认为垃圾收集器将匿名方法清理掉了,因为没有任何东西引用它了。使用Fabien的.Wait()方法允许我逐步执行程序并进行调试。我正在使用vs2017和netcore 2.1。


表达式无法评估。在调试器下无法创建 System.Threading.Tasks.Task 的新实例。出现错误 :( - Peyman Majidi

0
你可以使用异步方法的Result属性。
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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接