I am trying to use DI for my dbContext with MVC6/EF7 RC1.
I am instantiating my ContextTest (inherited from dbcontext) using [FromServices] attribute in the constructor of my TestService class
Sample code:
[FromServices]
public ContextTest _testContext { get; set; }
public TestService(ContextTest testContext)
{
_testContext = testContext;
}
public async GetData()
{
await _testContext.GetFunA();
await _testContext.GetFunB();
await _testContext.GetFunC();
}
Startup.cs
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ContextTest >(options => options.UseSqlServer(connection))
Exception:
Sporadically i am running into below exception
"An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point."
My 2 cents: Something to with Async calls (DI injects only 1 instance and i am trying to fire 3 queries in parallel.
Any suggestions?
Any chance you could provide a project that we can use to reproduce the issue? There is nothing obviously wrong in the code you provided.
My 2 cents: Something to with Async calls (DI injects only 1 instance and i am trying to fire 3 queries in parallel.
Are you referring to this code? If so, the queries aren't running in parallel since you have await'ed the calls (which is the correct thing to do since you can't run parallel operations on the same context instance).
await _testContext.GetFunA();
await _testContext.GetFunB();
await _testContext.GetFunC();
Closing as we have not heard back
I am now also seeing this error, I'll see if I can share a repro once I get some time. Maybe its something I am doing wrong, not sure yet.
@valcs007 you are using DbContext in TestService, which is possibly singleton and you end up using the one and only DbContext in your whole app. I've ran into same problem due to inaccurate design of my services: controller used some service injected through constructor to actually perform business logic, while this service was a singleton with DbContext injected through constructor again. So I ended up trying to operate on the same DbContext in every request. When there were few requests, it worked fine, but under some pressure bunch of exceptions begin to occur like
Invalid operation. The connection is closed.
An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point.
There is already an open DataReader associated with this Command which must be closed first.
The connection was not closed. The connection's current state is connecting.
The context cannot be viewed while the model is being created
Be careful and pay attention to register all of your services with correct DI lifetime management. Do not inject Scoped and Transient services into singletons. P.S. I hope my comment will someday help someone :)
I'd like to reopen this.
This can happen if for instance the web api controller has two methods (or same method in parallel) that are invoked in parallel using the same DbContext. Since the DbContext is lazily initialized, it will happen only when a user attempts a query, bringing a race condition with the exception in question.
So, imo, the DbContext::InitializeServices (or even DbContext::InternalServiceProvider::get) should be properly locked for the same instance and not throwing the exception. The second call should be simply blocked until the first finishes initialisation.
Here's a trace of what happens in my case:
System.InvalidOperationException: An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point.
at Microsoft.Data.Entity.DbContext.InitializeServices (IServiceProvider serviceProvider, Microsoft.Data.Entity.Infrastructure.DbContextOptions options) <0x6956ae0 + 0x001d3> in:0
at Microsoft.Data.Entity.DbContext+<>c__DisplayClass12_0.b__0 () <0x6956a80 + 0x00023> in :0
at Microsoft.Data.Entity.Internal.LazyRef1[T].get_Value () <0x69566e0 + 0x00025> in <filename unknown>:0 at Microsoft.Data.Entity.DbContext.get_ServiceProvider () <0x69569a8 + 0x00023> in <filename unknown>:0 at Microsoft.Data.Entity.DbContext.Microsoft.Data.Entity.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance () <0x6956968 + 0x00013> in <filename unknown>:0 at Microsoft.Data.Entity.Infrastructure.AccessorExtensions.GetService[TService] (IInfrastructure
1 accessor) <0x6956880 + 0x00030> in:0
at Microsoft.Data.Entity.Internal.InternalDbSet1[TEntity].<.ctor>b__2_0 () <0x69567b0 + 0x0001b> in <filename unknown>:0 at Microsoft.Data.Entity.Internal.LazyRef
1[T].get_Value () <0x69566e0 + 0x00025> in:0
at Microsoft.Data.Entity.Internal.InternalDbSet1[TEntity].System.Linq.IQueryable.get_Provider () <0x6956678 + 0x00017> in <filename unknown>:0 at System.Linq.Queryable.Any[TSource] (IQueryable
1 source, System.Linq.Expressions.Expression1 predicate) <0x69562a8 + 0x0002d> in <filename unknown>:0 at Max.Logic.Reference.Validator+<>c__DisplayClass2_0.<ValidateHtNumber>b__0 () <0x6955280 + 0x0013f> in <filename unknown>:0 at System.Threading.Tasks.Task
1[TResult].InnerInvoke () <0x1b81b80 + 0x00051> 24115 in:0
at System.Threading.Tasks.Task.Execute () <0x1935780 + 0x0004d> in:0
@durilka DbContext is not thread safe. It is never safe to have the same instance being accessed in parallel.
In that case the error message is misleading. Isn't it? Unless there are other possibilities to trigger it.
@durilka When objects that are not thread safe are used concurrency anything can happen. It just so happens you are hitting this error, which in a single-threaded use of the context says what it means, but you could be getting a null ref exception, any other type of exception, or no exception but corrupted data.
That's not my point. In DbContext initialisation method there's a check if the instance is currently being initialised. To my limited knowledge, this can only happen in case of multithreaded usage. If my understanding is correct, the error message should be explicit about the thread unsafety of the class. It's like warning the jaywalker that they forgot to look left before crossing the highway.
Your understanding is not correct. It can happen if you use the context, for example, to run a query while the context is being configured.
My last rfc in this topic. I promise.
Q.E.D. the exception can only be thrown if the same context is used from different thread.
``` C#
[Fact]
public void Context_cannot_be_used_in_OnConfiguring()
{
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
using (var context = new UseInOnConfiguringContext(serviceProvider))
{
Assert.Equal(
CoreStrings.RecursiveOnConfiguring,
Assert.Throws<InvalidOperationException>(() => context.Products.ToList()).Message);
}
}
private class UseInOnConfiguringContext : DbContext
{
private readonly IServiceProvider _serviceProvider;
public UseInOnConfiguringContext(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public DbSet<Product> Products { get; set; }
protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInternalServiceProvider(_serviceProvider);
Products.ToList();
base.OnConfiguring(optionsBuilder);
}
}
```
@ajcvickers How to deal in with the situation when we have several repositories trying to use a DbContext.
I have noticed, the exception from Above unit test and mine scenario is same.
System.InvalidOperationException: 'An attempt was made to use the context while it is being configured.
Below is some of my relevant code. Feel free to ask for anything relevant.
Note: When i have only one repository in my controller. It is working like a charm. But as soon as I have more than one repository in my controller. Both found themselves in race condition to create and configure DbContext.
Also note that If i make the DbContext lifetime to Transient. Issue is gone.
.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")),
ServiceLifetime.Scoped
);
@irsali It sounds very much like there are multiple threads accessing the same context instance. This will cause errors since the context instance is not thread-safe. Without knowing more about your application architecture it's hard to suggest the best way to deal with it, but using a transient service can be appropriate in some cases.
Had the same problem.
In my case I added a claims transformer implementation using
services.AddSingleton<IClaimsTransformation, ClaimsTransformer>();
since that class used a UserManager instance which used a dbcontext instance it threw this error.
after switching to
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
the problem seems to be fixed
I've run into the same problem. The error occurs when I try to initialize my application in the Program.Main
method. The service where the exception is thrown accepts DbContext
as constructor parameter, which is then used with Set<T>
to pull data for the initialization. I know, It looks like there is a problem with my initialization pipeline, however:
1) I don't think there is a way for my initialization pipeline to be run in parallel, since it's only used in the Main
method.
2) More interestingly - if I change the type of the context from DbContext
to SpecificDbContext
it suddenly works. However this is not an option as I need to use this service on several contexts.
I am even further confused by the fact that it doesn't always fail. Most of the times it does, but sometimes it works. I thought that something else was trying to use SpecificDbContext
at the same time and sometimes that operation took a bit longer to execute and thus SpecificDbContext
is available in this case. But that does not explain why everything works If I use SpecificDbContext
as parameter in my service.
Thanks!
@achobanov Please open a new issue and include a small, runnable project/solution that demonstrates the behavior you are seeing.
@ajcvickers I apologize, you stand correct. After another day of debugging the flow it turns out we were making parallel calls to the DbContext
. One thing I cannot figure is when I use DbContext
instead of MySpecificDbContext
errors are thrown much more frequently - like 9/10 attempts - while MySpecificDbContext
only throws let's say 1/20 or something similar. That's what threw me off in the first place.
Most helpful comment
@valcs007 you are using DbContext in TestService, which is possibly singleton and you end up using the one and only DbContext in your whole app. I've ran into same problem due to inaccurate design of my services: controller used some service injected through constructor to actually perform business logic, while this service was a singleton with DbContext injected through constructor again. So I ended up trying to operate on the same DbContext in every request. When there were few requests, it worked fine, but under some pressure bunch of exceptions begin to occur like
Be careful and pay attention to register all of your services with correct DI lifetime management. Do not inject Scoped and Transient services into singletons. P.S. I hope my comment will someday help someone :)