Dapper - 继续异步获取对象操作时任务取消

Dapper - Task Cancelled when continuing an asynchronous operation of fetching objects

我正在使用 .Net Core 5.0 和 Dapper 作为 ORM。

我有以下 C# 代码:

    public Task<IEnumerable<FooViewModel>> FetchAllFoos1(CancellationToken cancel = default)
    {
        string sql = "SELECT * FROM Foos";

        var context = new DbContext();
        var connection = context.GetConnection();
        var cmd = new CommandDefinition(sql, cancellationToken: cancel);

        return connection.QueryAsync<Foo>(cmd)
            .ContinueWith(x => x.Result.Select(y => ToFooViewModel(y)), cancel);
    }

此代码运行良好。

但是这个不是,我不明白为什么:

    public Task<IEnumerable<FooViewModel>> FetchAllFoos2(CancellationToken cancel = default)
    {
        string sql = "SELECT * FROM Foos";

        using (var context = new DbContext())
        {
            using (var connection = context.GetConnection())
            {
                 var cmd = new CommandDefinition(sql, cancellationToken: cancel);

                 return connection.QueryAsync<Foo>(cmd)
                        .ContinueWith(x => x.Result.Select(y => ToFooViewModel(y)), cancel);
            }
        }
    }

在等待 FetchAllFoos2 的结果时:var result = await FetchAllFoos2(),出现任务已取消异常。 它发生在 ContinueWith 中,当它试图获取 x.Result.

我知道这个问题是因为我正在使用关闭 context/connection 的“using”,但我不明白异常的内在原因。我喜欢用“using”来确保在我控制using时任何一次性物品都被清理干净,但我似乎不能在这里使用它..

你能帮我理解一下吗?

谢谢。

正如 TheGeneral 所指出的,核心问题是您使用的是 dangerous, low-level ContinueWith method。作为一般规则,使用 await 而不是 ContinueWith

public async Task<IEnumerable<FooViewModel>> FetchAllFoos2(CancellationToken cancel = default)
{
    string sql = "SELECT * FROM Foos";

    using (var context = new DbContext())
    {
        using (var connection = context.GetConnection())
        {
             var cmd = new CommandDefinition(sql, cancellationToken: cancel);

             var result = await connection.QueryAsync<Foo>(cmd);
             return result.Select(y => ToFooViewModel(y));
        }
    }
}

其中一个 problems of skipping async and await 是处置之类的事情发生在不正确的时间。对于 async 方法,处置发生在检索数据之后(在 await 之后)。对于非 async 方法,处理发生在查询 开始 之后,但(可能)在它 returns 其数据之前。