Gabriel Graitzer Gabriel Graitzer - 30 days ago 6
C# Question

Why is my thread getting stuck in Entity Framework SaveChangesAsync?

We have run into a strange issue with Entity Framework. We are attempting to add a new object to the database, and are doing this from a couple different locations. Both are using the following code loaded in through a nuget package:

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;
}


Doing this from within our console application works perfectly, however we are also trying to do this from a WebApi service endpoint (simplified test code given below) and when calling it from there the code gets stuck on the
var result = await context.SaveChangesAsync();
line.

Web Service Test Endpoint:

[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);
}


This test endpoint attempts to add the object with a Guid we know is already in the database now just for testing purposes but when run, the code makes it to the above mentioned
var result = await context.SaveChangesAsync();
line and then gets stuck. Nothing more is logged and the debugger stops there, never returning. No Exceptions are thrown, however the new row does get added to the database.

tl;dr Summary:

Console app can successfully call this repository method to add the object and can move on, the web service however can successfully add the object to the database but the code never returns from the
context.SaveChangesAsync()
method.

Things we have tried:

Changed the failing line in question to be
await Task.Run(() => context.SaveChangesAsync());
, attempted adding worker processes to the app pool of the service, and a few other things not worth mentioning.

Answer Source

Do not call .Result, it is a blocking call and, more important, it leads to a deadlock. use await instead and have your controller method return a Task. This is really the 101 of async/await. See this for an in depth explanation.