Problem: InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however, instance members are not guaranteed to be thread safe. This could also be caused by a nested query being evaluated on the client, if this is the case rewrite the query avoiding nested invocations.
Solution: When calling your method prefix it with an "await" in front, e.g. await yourObject.MethodName(); Chances are that you defined your function as an async hence when calling the function you are not using "await". The error tells you exactly the way it is, when you instantiated a class you also started the DB Context and then tried to use it on the same thread, that is a no-no, use awaits so that the call can run on a different thread. Hope this helps.
[Note]: Know your application, only use Async Await when you really need it, otherwise it will trip you and the application will be full of known bugs as Async Await bugs are hard to diagnose.
Things to Check in order to solve "A second operation started on this context" Error
- The cause of this error could be different from my scenario, that is why this error can drive a Software Developer Insane, if you try to understand it while you are kind of stressed about the error you will not make sense of it. Instead, look carefully in your Function hierarchy and find where you are calling the Database Context. It is considered a bad practice to call a database several times in the same function, why not prepare the Data you need at the Database Side and then just call the Database once in that function?
1. Check that your function is not calling a Database Context without awaiting a response. This can happen when you disregard the results of the function you are calling. For Example:
public async Task<IActionResults> MyFunction(){
//Calling the Database here
//This will cause problems when you try to make another call the Database down the line in the same Function
_ = meCallingTheDatabaseWithoutAwaitWhenThisFunctionIsAnAsyncFunction().ConfigurerAwait(false);
//Instead add an await to the function above and it will become as
//_ = await meCallingTheDatabaseWithoutAwaitWhenThisFunctionIsAnAsyncFunction().ConfigurerAwait(false);
//An Error happens Here.
var myNewData = await _myInterFace.GetData();
}
2. Add a ServiceLifetime.Transient to the #Service.AddContext in the Startup.cs class, this will allow the Database Context to be reused per session.
services.AddDbContext<MyDBContext>(options =>
options.UseSqlServer(
_configuration.GetConnectionString("DefaultConnection"), sqlServerOptionsAction: sqlOptions => {
sqlOptions.EnableRetryOnFailure();
}), ServiceLifetime.Transient);
Ways to Recreate the Issue:
1. This error comes about when you try to search the #database table that expects to return several data records and the Server Side streams those results to the
User Interface at the same time you are trying to send another database request.
- Look into your code and see if you have an Async Function inserting some sort of Audit Logs into the database, that could be the issue because if you call the Database Context on an Async Function and then tries to access the same Context on a none Async Function the error is thrown.
- To make it even worse, if an Async function has a #ConfigureAwait false this is even terrible because the code does not return to the Caller on the Main thread to report that the operation to the database is complete.
- Make sure you are not calling the database in the #async function and try to use the same context in the none async function.
Avoid these mistakes when working with Async Function, do not disregard the result while using an "Await" directive, the function won't be awaiting and might run Synchronously. Keep in mind if you want the results to be awaited. Always make sure that you add .ConfigurerAwait(false) in order for the results to be awaited
Luke said:
One way to solve this issue is by utilizing a ContinueWith function, this blocks the Main Thread resulting into Thread Starvation, however if you are doing some important operations you would rather wait for the operation to finish e.g. operation like inserting into the database then moving on. "System.InvalidOperationException: 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"