Asynchronous method exception: Invalid attempt to call CheckDataIsReady when reader is closed

Viewed 49
fail: Microsoft.EntityFrameworkCore.Query[10100]
      An exception occurred while iterating over the results of a query for context type 'DBR.Web.Context.DBRContext'.
      System.InvalidOperationException: Invalid attempt to call CheckDataIsReady when reader is closed.
         at Microsoft.Data.SqlClient.SqlDataReader.CheckDataIsReady(Int32 columnIndex, Boolean allowPartiallyReadColumn, Boolean permitAsync, String methodName)
         at Microsoft.Data.SqlClient.SqlDataReader.TryReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
         at Microsoft.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
         at Microsoft.Data.SqlClient.SqlDataReader.GetGuid(Int32 i)
         at lambda_method340(Closure , QueryContext , DbDataReader , ResultContext , SplitQueryResultCoordinator )
         at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
      System.InvalidOperationException: Invalid attempt to call CheckDataIsReady when reader is closed.
         at Microsoft.Data.SqlClient.SqlDataReader.CheckDataIsReady(Int32 columnIndex, Boolean allowPartiallyReadColumn, Boolean permitAsync, String methodName)
         at Microsoft.Data.SqlClient.SqlDataReader.TryReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
         at Microsoft.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout, Boolean allowPartiallyReadColumn)
         at Microsoft.Data.SqlClient.SqlDataReader.GetGuid(Int32 i)
         at lambda_method340(Closure , QueryContext , DbDataReader , ResultContext , SplitQueryResultCoordinator )
         at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

This exception occur when I try to go to get an object (GetByIdAsync()-method) in ASP.NET Core application (Blazor Server). It's used on a service, and that service call my EntityFramework Repository that uses the method GetByIdAsync(Guid id).

When I remove the asynchronous part of EFRepository: .ToListAsync() to .ToList(), it starts working with no issues. Does anyone know why? I want to keep them asynchronous somehow.

My UI:

protected override async Task OnInitializedAsync()
{
    if (CreateOrEdit is not "rediger" && CreateOrEdit is not "opret")
    {
        errorMessage = "Der er ingenting at se her. :(";
        isInvalidPath = true;

        return;
    }

    if (!string.IsNullOrWhiteSpace(WorkshopId))
    {
        Func<IQueryable<Workshop>, IIncludableQueryable<Workshop, object>> workshopIncludes = workshop => workshop.Include(x => x.Address!);

        ResponseDTO<WorkshopDTO> loadedWorkshop = await WorkshopService.GetByIdAsync(Guid.Parse(WorkshopId), isTrackingDisabled: false, includeProperties: workshopIncludes);

        if (loadedWorkshop.Success)
        {
            if (CreateOrEdit is "rediger")
            {
                workshopToEdit = loadedWorkshop.Content!;
            }
            else
            {
                workshopInputModel.Name = loadedWorkshop.Content!.Name;
                workshopInputModel.PhoneNumber = loadedWorkshop.Content!.PhoneNumber;
                workshopInputModel.AddressInputModel!.Street = loadedWorkshop.Content!.Address!.Street;
                workshopInputModel.AddressInputModel!.City = loadedWorkshop.Content!.Address.City;
                workshopInputModel.AddressInputModel!.PostCode = loadedWorkshop.Content!.Address.PostCode;
            }
        }
    }
}

My GetByIdAsync Service:

public async Task<ResponseDTO<TOUT>> GetByIdAsync(Guid entityId, bool isTrackingDisabled = true, Func<IQueryable<T>, IIncludableQueryable<T, object>>? includeProperties = null, Expression<Func<T, T>>? selector = null, CancellationToken cancellationToken = default)
{
    ResponseDTO<TOUT> responseDTO = await repository.GetByIdAsync(entityId, isTrackingDisabled, includeProperties, selector, cancellationToken);

    return responseDTO;
}

My GetByIdAsync EFRepository:

public async Task<ResponseDTO<TOUT>> GetByIdAsync(Guid id, bool isTrackingDisabled = true, Func<IQueryable<T>, IIncludableQueryable<T, object>>? includeProperties = null, Expression<Func<T, T>>? selector = null, CancellationToken cancellationToken = default)
{
    try
    {
        T requestedEntity = (await table.QueryHelper(selector: selector, includeProperties: includeProperties, isTrackingDisabled: isTrackingDisabled).ToListAsync(cancellationToken)).Find(entity => (Guid)entity.GetType().GetProperty("Id")!.GetValue(entity)! == id) ?? throw new ArgumentNullException(null);

        TOUT requestedEntityDTO = mapper.Map<TOUT>(requestedEntity);

        return new ResponseDTO<TOUT> { Success = true, Content = requestedEntityDTO };
    }
    catch (ArgumentNullException ex)
    {
        return new ResponseDTO<TOUT> { Success = false, ErrorMessage = $"Din anmodning blev ikke fundet - prøv igen.", ExceptionMessage = ex.Message, InnerExceptionMessage = ex.InnerException?.Message, ErrorType = ErrorType.EntityNotFound };
    }
    catch (OperationCanceledException ex)
    {
        return new ResponseDTO<TOUT> { Success = false, ErrorMessage = "Din anmodning blev annulleret.", ExceptionMessage = ex.Message, InnerExceptionMessage = ex.InnerException?.Message, ErrorType = ErrorType.CancellationTokenRequested };
    }
    catch (Exception ex)
    {
        return new ResponseDTO<TOUT> { Success = false, ErrorMessage = "Ubehandlet serverfejl. Kontakt server administrator.", ExceptionMessage = ex.Message, InnerExceptionMessage = ex.InnerException?.Message, ErrorType = ErrorType.Unhandled };
    }
}

My QueryHelper (extension method):

public static IQueryable<T> QueryHelper<T>(this DbSet<T> table, bool isTrackingDisabled = true, Func<IQueryable<T>, IIncludableQueryable<T, object>>? includeProperties = null, Expression<Func<T, bool>>? filter = null, Expression<Func<T, T>>? selector = null, Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null) where T : class
{
    IQueryable<T> query = table.AsSplitQuery();

    if (isTrackingDisabled)
    {
        query = query.AsNoTracking();
    }

    if (filter is not null)
    {
        query = query.Where(filter);
    }

    if (includeProperties is not null)
    {
        query = includeProperties(query);
    }

    if (selector is not null)
    {
        query = query.Select(selector);
    }

    if (orderBy is not null)
    {
        query = orderBy(query);
    }

    return query;
}

My 'Workshop' domain model:

public class Workshop : BaseEntity
{
    [StringLength(50)]
    public string Name { get; set; } = null!;

    public Guid AddressId { get; set; }

    [ForeignKey(nameof(AddressId))]
    public Address? Address { get; set; }

    [StringLength(15)]
    public string PhoneNumber { get; set; } = null!;

    public ICollection<Member>? Members { get; set; }

    public ICollection<Case>? Cases { get; set; }

    public ICollection<Specialization>? Specializations { get; set; }
}

My 'Address' domain model:

public class Address : BaseEntity
{
    [StringLength(50)]
    public string Street { get; set; } = null!;

    [StringLength(25)]
    public string City { get; set; } = null!;

    [Required]
    public short? PostCode { get; set; }
}

My DBRContext in Program.cs:

builder.Services.AddDbContext<DBRContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DBRContext") ?? throw new InvalidOperationException("Connectionstring 'DBRContext' was not found."), options => options.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));
0 Answers
Related