A second operation started on this context before a previous operation completed upgrading EF Core 2 to EF Core 3.1.3

asp.net-core asp.net-core-3.0 c# entity-framework-core


I just tried upgrading from EF Core 2 to EF Core 3. Every call I have is an Async Task<> method, but I'm still getting the A "Second operation started, see https://go.microsoft.com/fwlink/?linkid=2097913" error. I know it says to await every method, but doesn't that defeat the purpose of making async calls? Also, why does it work in EF Core 2 and not EF Core 3? If I have to use a diff db context, how can this be done with dependency injection in .net core 3?

// Async method that we will await later.
var softwareServiceCodeTask = _pricingCalcRepo.IsSoftwareServiceCodeAsync(jobsId)

pricingCalcInfo = await GetJobDetailsAsync(jobsId);

        private async Task<PricingCalculationInfo> GetJobDetailsAsync(int jobsId)
            return await (
                   from jobs in _contextProposal.PRP_Jobs
                   join service in _contextProposal.PRP_Service on jobs.ServiceId equals service.ServiceId
                   join proposal in _contextProposal.PRP_Proposal on service.ProposalId equals proposal.ProposalId
                   where jobs.JobsId == jobsId
                   select new PricingCalculationInfo
                       ContractYear = proposal.ContractYear,
                       BidCrewSize = jobs.BidCrewSize,
                       ServiceCode = service.ServiceCode,
                       Territory = jobs.Territory,
                       TotalPONIs = jobs.TotalPONIs,
                       WeekWorkHours = _appSettings.Value.WeekWorkHours,
                       NonProductiveHoursPerWeek = _appSettings.Value.NonProductiveHoursPerWeek
4/17/2020 1:02:05 PM

Accepted Answer

Is there a way to continue to tell EF core 3.1 to allow concurrency when I know it is safe. this worked in 2.1 so clearly this cannot be dismissed by simply saying db context has never allowed this by design and closing the question as a duplicate.

The DB context has never allowed that. I've never seen this kind of code work on any version of .NET Core. If it happened to work in 2.x, it was only "working" in the sense that the code was winning its race conditions and thus just getting lucky. Any change in performance - reduced memory, antivirus software, alternate network routing - could have caused this to fail. It's very important to recognize that the code is wrong and always has been.

My app has been running happily in production for a long time. Only after migrating to 3.1 has this become an issue. What has changed?

Probably some timing in the framework.

If this worked before when this 'wasn't allowed by design', is it possible that it is similarly not true now as well?

The race condition still exists. If your code happens to win the race condition, you won't see that exception.

Is this change truly impossible to work around or are there exceptions to the claim that the context doesn't allow this?

There's no workaround to force a dbcontext to work with multiple simultaneous requests. The normal pattern for doing simultaneous requests is to use multiple dbcontexts, one for each simultaneous request.

3/6/2020 11:24:09 PM

Popular Answer

A DbContext is cheap to create. By default, if you're injecting them into a scoped service, a new one is created for every request. But you can also create them yourself, while still leveraging .NET Core's DI framework.

Declare your DbContext in Startup.cs as you normally would. But the service (you are injecting services into your controllers, right?) that uses your DbContext can be a singleton instead of scoped, since it doesn't need to be injected with a new DbContext per-request. The background task started by the service can then use a ScopeFactory to create contexts as needed:

using (var scope = ScopeFactory.CreateScope())
using (var db = scope.ServiceProvider.GetRequiredService<MyDbContext>())
    // do stuff with db

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow