使用Dapper.NET异步API时如何尊重CommandTimeout?

3
我注意到在Dapper.NET中使用异步API时,我传递给扩展方法的命令超时值没有得到尊重。然后我发现SqlCommand.CommandTimeout的MSDN文档,似乎这是一些不被“支持”的东西。

在诸如BeginExecuteReader之类的异步方法调用期间,CommandTimeout属性将被忽略。

我在基类中使用以下方法。
public async Task<int> ExecuteAsync(string sql, object param = null,
            CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
    using (var connection = Connection)
    {
        Task<int> queryTask = connection.ExecuteAsync(sql, param, transaction, commandTimeout ?? CommandTimeoutDefault, commandType);
        int result = await queryTask.ConfigureAwait(false);
        connection.Close();
        connection.Dispose();
        return result;
    }
}

public async Task<IEnumerable<TEntity>> QueryAsync(string sql, object param = null, 
            CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
    using (var connection = Connection)
    {
        Task<IEnumerable<TEntity>> queryTask = connection.QueryAsync<TEntity>(sql, param, transaction, commandTimeout ?? CommandTimeoutDefault, commandType);
        IEnumerable<TEntity> data = await queryTask.ConfigureAwait(false);
        connection.Close();
        connection.Dispose();
        return data;
    }
}

假设 CommandTimeoutDefault 是30,我可以看到一个请求花费50秒仍然会被评估。

有没有想法如何使用异步的 Dapper.NET API 在超时时间内断开并处理连接?


小事一桩:您不需要Close/Dispose - 现有的代码已经通过using完成了这些操作。 - Marc Gravell
2个回答

1
这个问题很烦人,SqlClient本身并没有处理这个问题!然而,我想知道你能否使用以下方法解决:
- 传递取消令牌给Dapper(它接受它们) - 调用Task.Delay设置超时时间 - 调用Task.WhenAny同时传递Dapper任务和延迟任务 - 检查WhenAny返回的结果 - 如果是延迟任务,则发出取消信号并抛出自己的超时异常 - 确保任何由取消引起的异常都被清除处理
这可能有些丑陋,也许库应该封装这个问题,如果DB提供程序不尊重超时,那么只有库才能正确地处理正在进行的命令的取消。

0

这是在当前版本的Dapper中从异步方法调用的函数。正如您所看到的,CommandTimeout得到了很好的尊重。

internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader)
    {
      IDbCommand command = cnn.CreateCommand();
      Action<IDbCommand> init = CommandDefinition.GetInit(command.GetType());
      if (init != null)
        init(command);
      if (this.Transaction != null)
        command.Transaction = this.Transaction;
      command.CommandText = this.CommandText;
      if (this.CommandTimeout.HasValue)
      {
        command.CommandTimeout = this.CommandTimeout.Value;
      }
      else
      {
        int? commandTimeout = SqlMapper.Settings.CommandTimeout;
        if (commandTimeout.HasValue)
        {
          IDbCommand dbCommand = command;
          commandTimeout = SqlMapper.Settings.CommandTimeout;
          int num = commandTimeout.Value;
          dbCommand.CommandTimeout = num;
        }
      }
      System.Data.CommandType? commandType = this.CommandType;
      if (commandType.HasValue)
      {
        IDbCommand dbCommand = command;
        commandType = this.CommandType;
        int num = (int) commandType.Value;
        dbCommand.CommandType = (System.Data.CommandType) num;
      }
      if (paramReader != null)
        paramReader(command, this.Parameters);
      return command;
    }

enter image description here


1
我认为OP的意思是SqlClient不尊重超时时间。 - Marc Gravell
我曾经遇到过同样的问题。我使用了Dapper API的同步版本。但是无论如何,任何同步操作都可以转换为异步操作。 - Dmitry Dyachkov

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