registering DbContext with multiple parameters

2019-08-26 05:44发布

I'm trying to inject TenantProvider into DbContext

public class AppDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
{
    public int? _tenantId;

    public ITenantProvider _tenantProvider;

    public AppDbContext(
        DbContextOptions<AppDbContext> options,
        ITenantProvider tenantProvider
        )
    : base(options)
    {
        _tenantProvider = tenantProvider;
    }

but I don't understand how to register it correctly - if I put the breakpoint in the constructor - tenantProvider is null.

The bit from Startup.cs

services.AddDbContext<AppDbContext>(options => AppDbContextOptionsBuilder.Get());

the next line is required to inject the DbContext into a controller or a service (if I add ServiceLifetime.Scoped as a second parameter to the method above - AddDbContext - the feature doesn't work):

services.AddScoped(p => new AppDbContext(AppDbContextOptionsBuilder.Get(), p.GetService<ITenantProvider>()));

(Entity Framework is a separate project in my solution)


When using .AddScoped method - we can pass TenantProvider into constructor by resolving it using .GetService method.

Does anyone have an idea of how to resolve TenantProvider in .AddDbContext method?


Additional info:

I was trying to replace ITenantProvider in the constructor of DbContext with IHttpContextAccessor - the latter is registered as singleton. But the acessor parameter is still null.

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

1条回答
老娘就宠你
2楼-- · 2019-08-26 06:02

I don’t really understand what your AddScoped call is supposed to do. AddDbContext will already register the database context properly with the service collection. So when you resolve the context through dependency injection, additional dependencies will be automatically resolved.

So it should be enough to do this:

services.AddDbContext<AppDbContext>(options => …);

services.AddSingleton<ITenantProvider, TenantProvider>();

And then, you can depend on your AppDbContext using constructor injection, e.g. in your controllers.


Two notes though:

  1. When configuring options, you should modify the passed options object. So you should not just return AppDbContextOptionsBuilder.Get() but instead use the passed options object and edit that.

  2. You should really think about whether your database context having a dependency on your tenant provider is the right thing to do. As per SRP, your database should only do a single thing and that is provide database access.

    Depending on how your tenant provider affects your database access, it might make more sense to move this dependency up one level into some service that uses both the database context and the tenant provider to query data in the right way.

查看更多
登录 后发表回答