Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve exception message: The DbContext of type cannot be pooled because it does not have a single public constructor #18573

Closed
javico2609 opened this issue Oct 24, 2019 · 8 comments · Fixed by #22450
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@javico2609
Copy link

return exception

services.AddDbContextPool<DataAccessDbContext>();

 public DataAccessDbContext(DbContextOptions<DataAccessDbContext> options)
        : base(options)
        {

        }

        public DataAccessDbContext(DbContextOptions<DataAccessDbContext> options, IDateTimeService dateTimeService, ICurrentUserService currentUserService)
        : base(options)
        {
            _dateTimeService = dateTimeService;
            _currentUserService = currentUserService;
        }

Got Exceptions? Include both the message and the stack trace

System.InvalidOperationException: The DbContext of type 'DataAccessDbContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions.
   at Microsoft.EntityFrameworkCore.Internal.DbContextPool`1..ctor(DbContextOptions options)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__5`2.<AddDbContextPool>b__5_1(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__5`2.<AddDbContextPool>b__5_2(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at OpenIddict.EntityFrameworkCore.OpenIddictApplicationStoreResolver.Get[TApplication]()
   at OpenIddict.Core.OpenIddictApplicationCache`1..ctor(IOptionsMonitor`1 options, IOpenIddictApplicationStoreResolver resolver)

Further technical details

EF Core version: 2.2
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: 2.2
Operating system: Win10
IDE: Visual Studio 2019 16.3

@javico2609 javico2609 changed the title AddDbContextPool and DI exception The DbContext of type cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions Oct 24, 2019
@AndriySvyryd
Copy link
Member

We could improve the exception message:
The DbContext of type 'DataAccessDbContext' cannot be pooled because it does not have a public constructor accepting a single parameter of type DbContextOptions or has more than one constructor

@ajcvickers ajcvickers added this to the Backlog milestone Oct 25, 2019
@DaveSenn
Copy link

Just came across this error message after generating an EF context from an existing database using “dotnet ef dbcontext scaffold”. Scaffold creates two constructors one with a parameter of type DbContextOptions and another without any parameter.

I wondered why the context must have exactly one constructor with a single parameter of type DbContextOptions. Couldn’t EF/Pooling not just ignore all constructors with a different signature?

The requirement for just having one matching constructor means that one must delete the default constructor after every update/rebuild of the context using scaffold…which is somewhat annoying.

@ajcvickers
Copy link
Member

@DaveSenn We will look into allowing the parameterless constructor. It won't be functional in a pooling scenario, but it may be okay to ignore it.

@mhosman
Copy link

mhosman commented Aug 12, 2020

Why is a limitation to use services when using pooling?
For example I need a constructor to use a service so I can use UpdateValuesBeforeSaving to get the current userId in the session. That data is coming from outside. It is a question that I have. There's another way? Thank you.

@DaveSenn
Copy link

@ajcvickers That would be great. Ignoring the default constructor would solve our issue. Adding support for DI constructor injection as @mhosman suggests would also be ok... but i don't know how EF would pick the correct constructor? (maybe only one constructor with a parameter of type DbContextOptions allowed?)

@AndriySvyryd AndriySvyryd changed the title The DbContext of type cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions Improve exception message: The DbContext of type cannot be pooled because it does not have a single public constructor Aug 13, 2020
@AndriySvyryd
Copy link
Member

Related: #12604

@ajcvickers
Copy link
Member

@mhosman The DbContext is resolved once from the first service provider scope, and then that instance is re-used from the pool in future requests. This means that dependencies aren't resolved from the request, and would end up being stale. If you need other dependencies injected, then the solution is to not use pooling; it's unlikely that you will see any perf improvement from pooling in a scenario like this anyway.

@AndriySvyryd AndriySvyryd modified the milestones: Backlog, 5.0.0-rc2 Sep 8, 2020
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Sep 8, 2020
AndriySvyryd added a commit that referenced this issue Sep 8, 2020
AndriySvyryd added a commit that referenced this issue Sep 8, 2020
@ghost ghost closed this as completed in #22450 Sep 8, 2020
ghost pushed a commit that referenced this issue Sep 8, 2020
@ajcvickers ajcvickers modified the milestones: 5.0.0-rc2, 5.0.0 Nov 7, 2020
@ramon-garcia
Copy link

@mhosman The DbContext is resolved once from the first service provider scope, and then that instance is re-used from the pool in future requests. This means that dependencies aren't resolved from the request, and would end up being stale. If you need other dependencies injected, then the solution is to not use pooling; it's unlikely that you will see any perf improvement from pooling in a scenario like this anyway.

I understand your argument if one uses resources injected from the request scope. But if one uses singleton resources?

This limitation makes it very difficult to pass arguments to DbContext, for instance, for customizing it (such as table name or something depending on runtime configuration or command line).

At least, one should allow the programmer to provide a function that builds the DbContext from DbContextOptions.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants