Bahadir Emre
Bahadir Emre

Reputation: 11

I get "A second operation was started on this context before a previous operation completed" error just in one request

In my netcoreapp3.1 project I got the error just from one request I've recently added to my project: A second operation was started on this context 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. I couldn't find solution because I wrote await before every async request and my db context is transient.

My Db Context:

services.AddDbContext<MyContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
    },
    ServiceLifetime.Transient
    );

And this is where I got the error:

public class ProductDataRepository : UpdatableRepository<PRODUCT_DATA>, IProductDataDAL
{
    private readonly MyContext _context;

    public ProductDataRepository(MyContext context) : base(context)
    {
        _context = context;
    }

    public async Task<PRODUCT_DATA> GetProductById(string productId)
    {
        return await _context.PRODUCT_DATA.AsNoTracking().FirstOrDefaultAsync(pd => pd.PRODUCTID == productId);
    }

    public async Task<bool> IsProductMeltable(string productId)
    {
        // here is where I got the error
        return await _context.MELTABLE_PRODUCTS.AsNoTracking().AnyAsync(x => x.PRODUCTID.Equals(productId));
    }
}

And my DI:

services.AddScoped<IProductDataDAL, ProductDataRepository>();
services.AddScoped<IProductDataService, ProductDataManager>();

In manager:

public Task<bool> IsProductMeltable(string productId)
{
    return await _productDataDAL.IsProductMeltable(productId);
}

In controller:

myModel.IS_MELTABLE = await _commonService.ProductDataService.IsProductMeltable(productData.PRODUCTID);

I also changed my methods from async to sync but still got the same error.

Thanks for your help in advance

Upvotes: 1

Views: 2299

Answers (1)

Neil W
Neil W

Reputation: 9122

Without seeing all the places that these methods might be called, it is difficult to find the source.

But, two things that may help:

  1. The error reported does indicate that the same context is being called multiple times.

  2. Transient means that the DI container will provide a brand new instance each time one is requested.

Regarding that second point, be aware that you are injecting it into a 'scoped' service.

So, this means that whilst your context is 'transient' that does not mean a brand new context is provided each time it is called. It means that a new one is requested each time a context is requested.

As your other services are 'scoped' this means that they only request a context once per request scope. So, even though your context is registered as transient, the SAME context will be used throughout the lifetime of a scoped service that requests it.

I notice that your calling your repository from different layers. One from controller and one from a manager service. This is likely to cause challenges.

Try to keep each layer having different responsibilities.

Best to use the controller as a very thin layer to simply receive HttpRequests and immediately pass responsibilty over to a service layer to do business logic and interact with repositories.

Cleaning that up a little may help you identify the problem.

Upvotes: 3

Related Questions