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 其数据之前。
我正在使用 .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 其数据之前。