Efcore: Using pooling for multiple DbContexts causes exception

Created on 16 Aug 2017  路  20Comments  路  Source: dotnet/efcore

Exception message:
System.ArgumentException: Expression of type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MultiContext.Contexts.BContext]' cannot be used for constructor parameter of type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MultiContext.Contexts.AContext]' Parameter name: arguments[0]
Stack trace:
at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index) at System.Dynamic.Utils.ExpressionUtils.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments, String methodParamName) at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments) at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, Expression[] arguments) at Microsoft.EntityFrameworkCore.Internal.DbContextPool`1.CreateActivator(DbContextOptions options) at Microsoft.EntityFrameworkCore.Internal.DbContextPool`1..ctor(DbContextOptions options) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass22_0.b__0(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__2`1.b__2_1(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass22_0.b__0(ServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) at lambda_method(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.b__0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__22.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__7.MoveNext()

```c#
public class BContext : DbContext
{
public BContext(DbContextOptions options) : base(options) { }
}

public class AContext : DbContext
{
public AContext(DbContextOptions options) : base(options) { }
}


```c#
services.AddDbContextPool<AContext>(options =>
{
    options.UseInMemoryDatabase("AContext.InMemory");
});
services.AddDbContextPool<BContext>(options =>
{
    options.UseInMemoryDatabase("BContext.InMemory");
});

Further technical details

EF Core version: 2.0.0
Database Provider: Microsoft.EntityFrameworkCore.InMemory 2.0.0
Operating system: Mac OS X High Sierra
IDE: Rider

closed-fixed type-bug

Most helpful comment

Note for people hitting this: the workaround is to not use pooling. (Pooling can give some perf improvements, but if it is so much that it is needed by your app to even function then I'd be very interested to see the numbers. We will, of course, fix this, but probably not until the 2.1 release.)

All 20 comments

Got the same problem, using multiple DbContexts with .UseSqlServer.

Note for people hitting this: the workaround is to not use pooling. (Pooling can give some perf improvements, but if it is so much that it is needed by your app to even function then I'd be very interested to see the numbers. We will, of course, fix this, but probably not until the 2.1 release.)

@anpete There is a PR for this, but it looks like it needs some work.

i had the same problem, you need to change code https://github.com/aspnet/EntityFrameworkCore/pull/9465

Yepper, same issue here. All same symptoms...using more than one DbContext with AddDbContextPool causes exception.

Note for people hitting this: you should be able to workaround the issue by overriding the default DI configuration for DbContextPool to match this.

@leonidmln Can you explain in some detail what is wrong with the fix? We're planning to ship this soon, so if it doesn't work, then it would be really great to find out before we ship it, but we can't see what is wrong. Can you post some code that shows what is not working?

@ajcvickers While it does work, I believe the current fix is more like fixing the problem but not the "source" of the problem. You shouldn't even be able to throw a different kind of DbContextOptions in the constructor of DbContextPool<TContext>. It should be constraint to DbContextOptions<TContext>

@anpete @ajcvickers Also what @leonidmln said. The tests are not correct. SecondContext should have DbContextOptions<SecondContext> as parameter in the constructor because that is where the problem lies. Most people use DbContextOptions<T> in the constructor of their Context's if they have multiple Context's because that is how DI knows which Options object should be given to which Context. Otherwise wrong ConnectionStrings might be used.

Hi @maximtarasov, @ColinRaaijmakers, @leonidmln, @paultechguy, @Megasware128. We are gathering information on the use of EF Core pre-release builds. You reported this issue shortly after the release of 2.0.0 RTM. It would be really helpful if you could let us know:

  • Did you consider testing your code against the pre-release builds?
  • Was there anything blocking you from using pre-release builds?
  • What do you think could make it easier for you to use pre-release builds in the future?

Thanks in advance for any feedback. Hopefully this will help us to increase the value of pre-release builds going forward.

@ajcvickers Sorry for my late response.

I consciously waited for the release 2.0 before testing if AddDbContextPool worked correctly because I knew it would be in 2.0 release. Assuming that this 'just' would work.

Due to many different production sites, I prefer to test stable release rather than pre-builds.

I'm getting this error too. But is not clear to me know I can take advantage of this fix. I clumsily tried to download the repo and referenced the latest Microsoft.EntityframeworkCore in my project, but ended up mired in errors. What's the recommended way to implement this fix?

@nukuuk The fix has now been shipped yet. The easiest workaround is to use AddDbContext instead of AddDbContextPool.

What is the easiest way to test this fix for me?

Same here

I was very sad to retest this issue on 2.0.1 and got the same exception.
@ajcvickers can you please tell us when will this fix be included in a stable release?

@oncicaradupopovici The milestone assigned at the top of the issue is the indicator of what release a fix will be in--in this case 2.1. Unfortunately, the dates for 2.1 are not confirmed yet, so I can't share them publicly at this time.

@oncicaradupopovici yes I was disappointed to discover the same thing after installing 2.0.1

Anyone who is still looking at this, if you have multiple DbContext and want to implement the Pool for only one, place the DbContextPool as the last added context it appears to work and not throw the error.

``` c#
services.AddDbContext(options => options.UseNpgsql(connectionA); );

services.AddDbContext(options => options.UseNpgsql(connectionB));

services.AddDbContextPool(options => options.UseNpgsql(connectionC));

```

Might be a useful workaround for some.

Was this page helpful?
0 / 5 - 0 ratings