Async / Await в цикле Foreach (то есть цикл ef-моделей) генерирует ошибку - PullRequest
0 голосов
/ 01 марта 2019

У меня есть цикл foreach, и когда он первый раз обходит первый найденный элемент, он находит, но когда он переходит к следующему элементу, я получаю эту ошибку.

System.InvalidOperationException
  HResult=0x80131509
  Message=Error generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.LazyLoadOnDisposedContextWarning: An attempt was made to lazy-load navigation property 'Company' on entity type 'RecurringInvoiceTemplateProxy' after the associated DbContext was disposed.'. This exception can be suppressed or logged by passing event ID 'CoreEventId.LazyLoadOnDisposedContextWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition`2.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, WarningBehavior warningBehavior, TParam1 arg1, TParam2 arg2, Exception exception)
   at Microsoft.EntityFrameworkCore.Internal.CoreLoggerExtensions.LazyLoadOnDisposedContextWarning(IDiagnosticsLogger`1 diagnostics, DbContext context, Object entityType, String navigationName)
   at Microsoft.EntityFrameworkCore.Internal.LazyLoader.ShouldLoad(Object entity, String navigationName, NavigationEntry& navigationEntry)
   at Microsoft.EntityFrameworkCore.Internal.LazyLoader.Load(Object entity, String navigationName)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.LazyLoadingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.RecurringInvoiceTemplateProxy.get_Company()
   at SourceLine.Api.Services.InvoicingService.<>c__DisplayClass48_0.<GenerateRecurringInvoicesAsync>b__0(CustomerDto x) in 1299
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at SourceLine.Api.Services.InvoicingService.<GenerateRecurringInvoicesAsync>d__48.MoveNext() in line 1299
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

мой запрос

 return dbContext.RecurringInvoiceTemplates.Include(x => x.Company)
                                              .Include(x => x.RecurringInvoiceFrequency)
                                              .Where(x => x.NextRun.Date.CompareTo(currentTime.Date) <= 0).ToList();

Запрос умирает

    foreach (var r in recurringInvoices){
     var foundCustomer = allCustomers.FirstOrDefault(x => x.Id == r.Company.Identifier);
}

Обновление

Проблема может быть на самом деле из-за этого

public async void Get(){

    var recurringInvoices = dbContext.RecurringInvoiceTemplates.Include(x => x.Company)
                                                  .Include(x => x.RecurringInvoiceFrequency)
                                                  .Where(x => 
    var allCustomer = new List<Dto>(){
        new Dto(){
            Id = 1
        }
    }

    foreach (var r in recurringInvoices)
    {
        //allcustomers is not en EF object, just a dto.
        var foundCustomer = allCustomers.FirstOrDefault(x => x.Id == r.Company.Identifier);

        if (foundCustomer != null)
        {

                var ApiKey = configuration["SendGrid:Key"];
                var sendGridClient = new SendGridClient(ApiKey);

                var msg = new SendGridMessage();
                msg.SetFrom(new EmailAddress("example@test.com, "Example User"));


                msg.SetTemplateId("d-f06bfad7374b4a3cb2ccbf846d8e96a4");


                var dynamicTemplateData = new SendInvoiceTemplateDto
                {
                    Subject = "a",
                    Body = "b"
                };

                msg.SetTemplateData(dynamicTemplateData);

                var response = await sendGridClient.SendEmailAsync(msg);
            }
        }
}

Так что похоже, так как яя использую async это избавляет мой dbContext?

Edit 2

Я не понимаю, но когда я использую

 var response = sendGridClient.SendEmailAsync(msg);
response.Wait();

, я больше не вижу этой проблемы.

1 Ответ

0 голосов
/ 01 марта 2019

Так что, похоже, поскольку я использую async, он избавляется от моего dbContext?

Ваша проблема связана с async void.Вам следует избегать async void.Одна из проблем, вызванных async void, заключается в том, что вызывающий этого метода не может знать , когда он завершился.Таким образом, вызывающая сторона просто продолжает выполнение, в конечном итоге завершая HTTP-запрос и срывая контроллер (и все, что у вас есть, в него вставлена ​​зависимость), удаляя DbContext и вызывая это исключение, потому что ваш код все еще выполняется .

Решение состоит в том, чтобы изменить async void на async Task и получить вызывающего абонента await Task, возвращенного с Get.Если Get является действием контроллера, то вам просто нужно изменить async void на async Task;ASP.NET автоматически обработает Task правильно.

...