2

How to use more than one DBContext in a controller, I tried to overload the construktors in different ways?

Some Controller:

public C1(DBContext1 a, DBContext2 b, DBContext3 c)
{ 
}
 //public C1(DBContext1 a)
 //{ 
 //}
 //public C1(DBContext2 b)
 //{
 //}
 //public C1(DBContext3 c)
 //{
 //}

StartUp.cs:

services.AddDbContext<DBContext1>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

services.AddDbContext<DBContext2>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

services.AddDbContext<DBContext3>(options =>
options.UseSqlServer(new string(K.ConnectionString))
);

I found this, but it seems to be outdated

Error(, when Calling the constructor by the frontend):

An unhandled exception has occurred while executing the request.

Exception: System.InvalidOperationException: The DbContextOptions passed to the DBContext1 constructor must be a DbContextOptions. When registering multiple DbContext types make sure that the constructor for each context type has a DbContextOptions parameter rather than a non-generic DbContextOptions parameter. at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at _4_DWH.DBContext1..ctor(DbContextOptions options) in D:...\DBContext1.cs:line 43 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.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.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__CreateController|0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

DBContext:

public class DBContext1 : DbContext
{
    // ...

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(new string(sameConnectionString));
    }

    public DBContext1() : base()
    {

    }

    public DBContext1(DbContextOptions options) : base(options)
    {
    }
}
4
  • Does this: stackoverflow.com/questions/56937314/… helps you ? Commented Apr 5, 2021 at 8:39
  • 1
    Why does this not work already? Show a screenshot indicating the problem/how you know there is a problem. Show us any code creates the controller (it shouldn't; the DI should do it). Show us the controller DI registration. Show the values of the arguments to the constructor. Tell us any error messages Commented Apr 5, 2021 at 8:40
  • See following : stackoverflow.com/questions/13291025/… Commented Apr 5, 2021 at 8:40
  • 1
    you need to use DbContextOptions<DbContext1>, DbContextOptions<DbContext2> ... instead of just DbContextOptions (in the constructors). Commented Apr 5, 2021 at 9:23

1 Answer 1

3
  1. Create DB contexts
public class DBContext_A : DbContext
{
    public DBContext_A(DbContextOptions<DBContext_A> options) : base(options)
    {
    }
}

public class DBContext_B : DbContext
{
    public DBContext_B(DbContextOptions<DBContext_B> options) : base(options)
    {
    }
}

public class DBContext_C : DbContext
{
    public DBContext_C(DbContextOptions<DBContext_C> options) : base(options)
    {
    }
}
  1. Define a connection string for each DBContext:
{
  "ConnectionStrings": {
    "Connection_A": "Server=(localdb)\\mssqllocaldb;Database=DB_A;Trusted_Connection=True;...",
    "Connection_B": "Server=(localdb)\\mssqllocaldb;Database=DB_B;Trusted_Connection=True;...",
    "Connection_C": "Server=(localdb)\\mssqllocaldb;Database=DB_C;Trusted_Connection=True;...",
  }
}
  1. Register in startup:
services.AddDbContext<DBContext_A>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_A"));
});

services.AddDbContext<DBContext_B>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_B"));
});

services.AddDbContext<DBContext_C>(ops =>
{
    ops.UseSqlServer(Configuration.GetConnectionString($"Connection_C"));
});

  1. Inject into controller:
public FooController : Controller
{
    private readonly DBContext_A _context_A;
    private readonly DBContext_B _context_B;
    private readonly DBContext_C _context_C;

    public FooController(
            DBContext_A context_A, 
            DBContext_B context_B, 
            DBContext_C context_C)
    {
        _context_A = context_A;
        _context_B = context_B;
        _context_C = context_C;
    }
}

Additional best-practice for Code First approach:

Create a class library for each context, so when you apply migrations each context will have its own migrations folder in its own project.

  • Solution
    • MainProject
      • startup.cs
    • ClassLibrary_A
      • DbContext_A.cs
      • Migrations // folder
    • ClassLibrary_B
      • DbContext_B.cs
      • Migrations // folder
    • ClassLibrary_C
      • DbContext_C.cs
      • Migrations // folder

While applying migrations in a multi context solution;

  • From solution explorer, Set the main project (with startup.cs) as "Startup project"
  • Set the relevant ClassLibrary_A or B or C from the package manager console as "Default project"
  • Add the target context to each cmd as below:
PM > add-migration Init -Context DBContext_A
PM > update-database -Context DBContext_A

PM > add-migration Init -Context DBContext_B
PM > update-database -Context DBContext_B

PM > add-migration Init -Context DBContext_C
PM > update-database -Context DBContext_C

Alternatively, you may use the full PM cmd as below:

PM > add-migration Init -Context DBContext_A -Project ClassLibrary_A -StartupProject MainProject
PM > update-database -Context DBContext_A -Project ClassLibrary_A -StartupProject MainProject

PM > add-migration Init -Context DBContext_B -Project ClassLibrary_B -StartupProject MainProject
PM > update-database -Context DBContext_B -Project ClassLibrary_B -StartupProject MainProject

PM > add-migration Init -Context DBContext_C -Project ClassLibrary_C -StartupProject MainProject
PM > update-database -Context DBContext_C -Project ClassLibrary_C -StartupProject MainProject
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.