Home > Software design >  I get an error when I want to select in constructor in ASP.NET Core Web API
I get an error when I want to select in constructor in ASP.NET Core Web API

Time:11-26

I get an error in my ASP.NET Core Web API project when want to select all content:

System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext

This is my contentService:

    private IContentRepository contentRepository;
    private DbContext_CMS dbContext;
   
    public ContentService(IContentRepository contentRepository, DbContext_CMS dbContext )
    {
        this.contentRepository = contentRepository;
        this.dbContext = dbContext;
    }

    public IEnumerable<ContentInfoDTO>  GetAllContent()
    {
        try
        {
            IQueryable<Content> contents = contentRepository.GetAll();

            IEnumerable<ContentInfoDTO> result = contents.Select(content => new ContentInfoDTO(content)).ToList();
            return result;
        }
        catch (Exception ex)
        {               
            return null;
        }
    }
   

This is ContentInfoDTO.cs:

public class ContentInfoDTO
{
    public ContentInfoDTO(Content content)
    {
        try
        {
            this.Id = content.Id;
            this.Title = content.Title;
            this.Description = content.Description;
          
            this.BodyHtml = content.BodyHtml;
            this.ContentCategories = content.ContentCategories.Select(category => new CategoryInfoDTO(category.FkCmsCategory)).ToList(); //this line error
            
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    public int Id { get; set; }
    public string? Title { get; set; }
    public string? Description { get; set; }       
    public string? BodyHtml { get; set; }
  
    public ICollection<CategoryInfoDTO>? ContentCategories { get; set; }
}

This is my CategoryInfoDTO:

public class CategoryInfoDTO
{
    public CategoryInfoDTO(Category? category)
    {
        if (category != null)
        {
            this.Id = category.Id;
            this.Title = category.Title;
            this.Description = category.Description;
            this.FkParentId = category.FkParentId;
        }
    }

    public int Id { get; set; }
    public string? Title { get; set; }
    public string? Description { get; set; }
    public int? FkParentId { get; set; }
}

And this is my dbContext configured:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder
                      .UseLazyLoadingProxies()                        
                      .UseSqlServer("connectionString");
        }
}

I also fixed dependency injection, but it didn't work.

service.AddDbContext<DbContext_CMS>();

CodePudding user response:

In contentService:

IEnumerable<ContentInfoDTO> result = contents.Select(content => new ContentInfoDTO(content)).ToList();

in the Select method you start by getting Content entities from the database. At the moment you start getting your first Content, the DbContext instance provided to you by Dependency Injection is in use.

Next, while still inside the Select method, you take the Content entity, create a new ContentInfoDTO object and pass the entity into the constructor. In the constructor of ContentInfoDTO, specifically at the line you get your error,

this.ContentCategories = content.ContentCategories.Select(category => new CategoryInfoDTO(category.FkCmsCategory)).ToList();

you access the ContentCategories property, which is a navigation property belonging to Content. Since the Content entity you passed into the constructor was provided by EF Core, it is being tracked by EF Core, which means when you tried to perform an operation on ContentCategories property, EF Core tried to perform a lazy loading of all the Category entities related to that Content instance. However, since we're still inside the first Select method and the DbContext instance is still in use there, we tried to access the same DbContext from different places at the same time, hence the error.

You could force the retrieval of the ContentCategories collection earlier using the Include method and see if that solves the problem - see eager loading.

Also, I don't think you need to inject your DbContext in contentService, since you seem to use the repository pattern and retrieve your entities from there, I assume the DbContext is already injected into your repository instance.

Edit : it should be lazy loading instead of explicit loading. Also that's assuming that the lazy loading related package is installed and configuration has been done and that the navigation property is virtual. If your situation doesn't cover any of the requirements, your error may be from something else

  • Related