How to find the cause of "second operation started on this thread..." error messsage

32 Views Asked by At

We are converting an old .Net Framework 4.7.2 MVC app to .Net 5. Until everything is converted, we have a number of the projects set up as NetStandard 2. One of those projects is our data layer and the latest version of EF Core it can use is 3.1.

In the web app, there's a page that when loaded, has 2 ajax calls. When the page loads one of the 2 calls fail with the error - A second operation started on this context before a previous operation completed. I've gone through both methods from front to back and everything is set up properly with async/await. I've set up logging so I can see every query that's executed by the web app and verified nothing else is running that should already be using the thread.

This was not a problem in the .Net Framework/EF6 version so I've been banging my head against the wall for two days trying to trace what's causing this.

Since these are ajax calls, aren't they all considered their own request? If so, I would expect the DI to provide a new context for each one.

Here's the javascript.

const loadPerDiem = () => {
    return new Promise((resolve, reject) => {
        fetch("/Quote/PerDiemRates")
            .then(r => {
                let json = r.json();
                json.then(d => {
                    d.forEach((x) => {
                        var enumId = x.PerDiemEnumerationId;
                        var rate = x.Rate;

                        perDiemItems.forEach((y) => {
                            if (y.id == enumId)
                                y.rate = rate;
                        });
                    });
                    resolve(true);
                })
            });
    })
}

const getNetworks = () => {
    return new Promise((resolve, reject) => {
        fetch("/Quote/GetNetworks")
            .then(r => {
                r.json()
                    .then(d => {
                        networks = d;
                        resolve(true);
                    })
            });
    })
}

Promise.all([loadPerDiem(), getNetworks()])
        .then(r => {
            fetch("/QuoteAddOns/GetAllActive?v=" + new Date().getTime())
                .then(a => {
                    loadSavedQuotes();
                })
        })

And here are the endpoints being called.

public async Task<ActionResult> PerDiemRates()
{
    return Json(await _onlineQuoteParameterService.PerDiemRatesAsync());
}

public async Task<JsonResult> GetNetworks()
{
    return Json(await _splitNetworkService.GetNetworksForDropDownAsync());
}

Here's the slimmed down version of our registry file where the context is registered for the DI container.

public void Define()
{
    Scan(
        scan =>
        {
            scan.SingleImplementationsOfInterface();
            scan.TheCallingAssembly();

            scan.Assembly(ApplicationAssemblyName);
            foreach (var name in Assemblies)
                scan.Assembly(name);

            scan.AddAllTypesOf<IEventSubscriber>();
            scan.WithDefaultConventions();
        });

    var entityNotifier = new EntityUpdateNotifier(channelService, exchangeService);
    For<IFHDbContext>().Use(new FHDbContext(DataSources.FHDataSource, entityNotifier));

}
0

There are 0 best solutions below