使用语句中的Dapper异步查询需要一个开放且可用的连接

时间:2017-08-22 19:39:23

标签: c# asp.net asynchronous asp.net-web-api dapper

我在我的项目中使用Dapper。我的项目包括3层。 API,业务和存储库层。

我想要用户异步查询dapper。

以下是每一层中的代码。

在存储库层

public Task<int> ChangeStatus(DriverStatus driverStatus)
        {
            using (IDbConnection connection = DapperConnection)
            {
                var updateQuery = @"UPDATE [dbo].[DriverLocation] Set [Latitude]=@Latitude, [Longitude]=@Longitude, [IsOnline]=@IsOnline Where [DriverId]=@DriverId";
                return connection.ExecuteAsync(updateQuery, new
                {
                    Latitude = driverStatus.Latitude,
                    Longitude = driverStatus.Longitude,
                    IsOnline = driverStatus.IsOnline,
                    DriverId = driverStatus.DriverId
                });
            }
        }

现在我的业务层方法调用存储库方法。

public Task<int> ChangeStatus(DriverStatus driverStatus)
        {
            try
            {
                //Some Code here.
               return driverRepository.ChangeStatus(driverStatus);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                return Task.FromResult<int>(0);
            }
        }

现在API方法调用业务层方法。

public async Task<IHttpActionResult> ChangeStatus(DriverStatus driverStatus)
        {
            ApiResponse apiResponse = new ApiResponse();
            var isUpdated = await driverBl.ChangeStatus(driverStatus);
            if(isUpdated > 0)
            {
                apiResponse.Message = "Driver status changed successfully.";
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, apiResponse));
            }
            else
            {
                apiResponse.Message = "Driver status could not be changed.";
                return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, apiResponse));
            }

        }

因为我只在我的API方法中使用了await关键字,所以在返回结果之前我的连接对象可能被处理掉了,所以它让我误以为错误。

  

BeginExecuteNonQuery需要一个开放且可用的连接。该   连接的当前状态已关闭。

如何使用using语句使用dapper的异步方法?

2 个答案:

答案 0 :(得分:0)

使用async / await,您需要确保在整个调用堆栈中使用它。

您的回购图层应如下所示:

public async Task<int> ChangeStatus(DriverStatus driverStatus)
{
    using (IDbConnection connection = DapperConnection)
    {
        var updateQuery = @"UPDATE [dbo].[DriverLocation] Set [Latitude]=@Latitude, [Longitude]=@Longitude, [IsOnline]=@IsOnline Where [DriverId]=@DriverId";
        return await connection.ExecuteAsync(updateQuery, new
        {
            Latitude = driverStatus.Latitude,
            Longitude = driverStatus.Longitude,
            IsOnline = driverStatus.IsOnline,
            DriverId = driverStatus.DriverId
        });
    }
}

你的BLL层应如下所示:

public async Task<int> ChangeStatus(DriverStatus driverStatus)
{
    try
    {
        //Some Code here.
        return await driverRepository.ChangeStatus(driverStatus);
    }
    catch (Exception ex)
    {
        Logger.Error(ex);
        return 0;
    }
}

答案 1 :(得分:0)

您的问题是您在存储库层中省略了异步并等待使用,并且当它与using语句结合使用时,它将导致不可预测的行为。

当您调用connection.ExecuteAsync时,您启动了一个依赖于连接的任务,因此连接必须保持打开状态,并且只要任务未完成就不应该处理。 在你的情况下,你在启动任务后立即返回并立即处理连接(因为你有一个using语句,一旦连接超出范围就会处理连接),所有这一切都发生在任务之前已经完成了。

为了防止在任务完成之前处理连接,您需要以异步方式等待&#34;使用async和await关键字的操作,并且仅在await返回方法的结果之后。

public async Task<int> ChangeStatus(DriverStatus driverStatus)
{
    using (IDbConnection connection = DapperConnection)
    {
        var updateQuery = @"UPDATE [dbo].[DriverLocation] Set [Latitude]=@Latitude, [Longitude]=@Longitude, [IsOnline]=@IsOnline Where [DriverId]=@DriverId";
        return await connection.ExecuteAsync(updateQuery, new
        {
            Latitude = driverStatus.Latitude,
            Longitude = driverStatus.Longitude,
            IsOnline = driverStatus.IsOnline,
            DriverId = driverStatus.DriverId
        });
    }
}

有关Eliding Async and Await Stephen Cleary博客文章中有关该主题的更多信息。

您还有一个错误,在您的业务层中,您的try catch块无法正常工作,以便从您拥有to block or await it的异步方法中捕获异常:

public async Task<int> ChangeStatus(DriverStatus driverStatus)
{
    try
    {
       //Some Code here.
       return await driverRepository.ChangeStatus(driverStatus);
    }
    catch (Exception ex)
    {
        Logger.Error(ex);
        return 0;
    }
}

最后一件与此无关的事情是,在业务层吞下例外并向上层做出错误陈述真的是一个好主意吗?