为什么我的线程陷入Entity Framework SaveChangesAsync?

时间:2017-08-23 16:47:46

标签: c# .net multithreading entity-framework asp.net-web-api

我们遇到了Entity Framework的一个奇怪问题。我们正在尝试向数据库添加一个新对象,并且正在从几个不同的位置执行此操作。两者都使用通过nuget包加载的以下代码:

public async Task<Guid> AddRecurrenceHistoryAsync(RecurrenceHistory recurrenceHistory, Guid recurrenceId)
{
    _logger.DebugLogInformation("+");

    try
    {
        using (RecurringPaymentsContext context = new RecurringPaymentsContext())
        {
            var recur = context.RecurringPayments.Single(r => r.Id == recurrenceId);
            if (recur.RecurrenceHistories == null)
            {
                _logger.DebugLogInformation($"No existing histories found");
                recur.RecurrenceHistories = new List<RecurrenceHistory>();
            }
            recur.RecurrenceHistories.Add(recurrenceHistory);
            _logger.DebugLogInformation($"Saving Changes");
            var result = await context.SaveChangesAsync();
            _logger.DebugLogInformation($"Changes Saved result: {result}");
        }
    }
    catch (Exception e)
    {
        _logger.DebugLogError(e.ToString());
        throw;
    }

    _logger.DebugLogInformation(string.Format("- return: {0}", recurrenceHistory.Id));
    return recurrenceHistory.Id;
}

在我们的控制台应用程序中执行此操作非常有效,但是我们也尝试从WebApi服务端点(下面给出的简化测试代码)执行此操作,并且从那里调用它时代码卡在var result = await context.SaveChangesAsync();上线。

Web服务测试端点:

[HttpGet]
[Route("test")]
public HttpResponseMessage Test()
{
    var paymentHistory = new RecurrenceHistory()
    {
        SystemId = Guid.NewGuid(),
        TotalAmount = -1
    };
    _logger.DebugLogInformation("Adding recurrence history");
    paymentHistory.Id = _recurrenceHistoryRepository.AddRecurrenceHistoryAsync(paymentHistory, Guid.Parse("3c412e1b-7a87-e711-910c-0050569b7221")).Result;

    return Request.CreateResponse(true);
}

此测试端点尝试使用我们知道已在数据库中的Guid添加对象,现在仅用于测试目的,但在运行时,代码将进入上述var result = await context.SaveChangesAsync();行,然后卡住。没有更多的记录,调试器停在那里,永远不会返回。不会抛出异常,但新行确实会添加到数据库中。

tl; dr摘要:

控制台应用程序可以成功调用此存储库方法来添加对象并可以继续,但是Web服务可以成功地将对象添加到数据库,但代码永远不会从context.SaveChangesAsync()方法返回。

我们尝试过的事情:

将有问题的失败行更改为await Task.Run(() => context.SaveChangesAsync());,尝试将工作流程添加到服务的应用池中,以及其他一些值得一提的事情。

1 个答案:

答案 0 :(得分:6)

不要拨打.Result,这是一个阻止呼叫,更重要的是,它会导致死锁。请改用await,让控制器方法返回Task。这实际上是异步/等待的101。有关详细说明,请参阅this

相关问题