Home > Enterprise >  Getting second operation Db context after second request
Getting second operation Db context after second request

Time:10-29

I'm working on an ASP.NET Core MVC application and I have a view who do a post request as:

  $.ajax({
                    url:'/Advertisers/ActiveAdvertiser?id=' id '&isActive=' !isActive,
                    method: 'POST',
                    success: function(r){
                        Swal.fire("Inactivated!", "Advertiser inactivated successfully", "success");
                    },
                    error: function (request) {
                        console.log(request.responseText)
                        Swal.fire("Error!", "Something went wrong, please try again`", "warning");
                    }
                });

Controller:

[HttpPost]
public async Task<JsonResult> ActiveAdvertiser(int id, bool isActive)
{
    var advertiser = await _advertisersService.GetAdvertiserByAdvertiserIdAsync(id);

    if (advertiser != null)
    {
        var model = AssingAdvertiserViewModel(advertiser, id);
        model.IsActive = isActive;

        var result = await _advertisersService.UpdateAdvertiserAsync(model, GetCurrentUserAsync().Id);

        if (result != null)
        {
            return Json(new { result = "OK" });
        }
    }

    return Json(new { result = "BadRequest" });
}

Post method services:

public Task<Advertiser?> GetAdvertiserByAdvertiserIdAsync(int advertiserId)
{
    return _db.Advertisers
              .Include(a => a.Address)
              .Include(pc => pc.PrimaryContact)
              .Include(ac => ac.AlternateContact)
              .FirstOrDefaultAsync(x => x.AdvertiserId == advertiserId);
}

private AdvertiserViewModel AssingAdvertiserViewModel(Advertiser advertiser, int id)
{
    var model = new AdvertiserViewModel()
    {
        //Fill model here
    };

    return model;
}

public async Task<Advertiser?> UpdateAdvertiserAsync(AdvertiserViewModel model, int updatedById)
{
    var advertiser = await GetAdvertiserByAdvertiserIdAsync(model.AdvertiserId);

    if (advertiser is null)
        return null;

    advertiser.Name = model.Name;

    // fill model here

    await _db.SaveChangesAsync();

    return advertiser;
}

The problem is I do the first request, and it returns Success with any issues, but if I try to do a second one, it throws an exception:

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.

If I stop the project and run it again it works one time again and in the second time get the error again

I read about this issue in other questions, and apparently is because you don't use the await services, I check my code and almost everything uses await. Can someone see something that I don't see? Regards

CodePudding user response:

You could check this document for how to handle this error:

Therefore, always await async calls immediately, or use separate DbContext instances for operations that execute in parallel.

So you could check if misssing the await keyword on async operation

and use separate Dbcontext instances with DbcontextFactory as below:

regist the factory in service collection:

builder.Services.AddDbContextFactory<SomeContext>();

inject it into controller/Service/Somewhereelse:

public class SomeEntitiesController : Controller
        {
            
            private readonly IDbContextFactory<SomeContext> _factory;
            public SomeEntitiesController(IDbContextFactory<SomeContext> factory)
            {
                
                _factory = factory;
            }
          }

create a new dbcontext:

_factory.CreateDbContext()

CodePudding user response:

I solve this by adding ServiceLifetime.Transient into my services as:

services.AddDbContext<ApplicationDbContext>(
            options =>
                options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbConnection")),
            ServiceLifetime.Transient
        );
  • Related