0

我正在使用 .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(),我有一个 Task Canceled 异常。它发生在 ContinueWith 中,当它试图获取 x.Result 时。

我知道问题出在因为我使用“使用”来关闭上下文/连接,但我不明白异常的内在原因。我喜欢使用“使用”来确保在我无法控制使用时清洁任何一次性物品,但似乎我不能在这里使用它..

你能帮我理解吗?

谢谢你。

4

1 回答 1

2

正如 TheGeneral 指出的那样,核心问题是您使用的是危险的低级ContinueWith方法。作为一般规则,使用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));
        }
    }
}

跳过asyncawait的问题之一是处置之的事情发生在不正确的时间。对于该async方法,处置发生在检索数据之后(在 之后await)。对于非async方法,处理发生在查询开始之后但(可能)在它返回其数据之前。

于 2021-08-21T01:26:12.947 回答