仅在调用控制器操作时才知道数据库名称时,注入DbContext [英] Inject DbContext when database name is only know when the controller action is called

查看:101
本文介绍了仅在调用控制器操作时才知道数据库名称时,注入DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WebAPI/EF Core后端应用程序,具有多个可能要连接的客户端数据库(每个数据库都有相同的架构,但一次只能一个).

I have a WebAPI/EF Core back-end application with several possible client databases to connect to (each of the same schema, but only one at a time).

直到访问WebAPI控制器,才知道要连接到哪个数据库的知识.到那时,使用starup.cs文件的ConfigureServices()方法中对services.AddDbContext<>()的调用将DBContext作为可注入对象添加已经为时已晚.

Knowledge of which database to connect to will not be known until a WebAPI controller is accessed. By that time, it will be too late to add the DBContext as an injectable object using the call to services.AddDbContext<>() in the ConfigureServices() method of the starup.cs file.

由于每个请求都隔离了DbContext的每个实例,因此直接从控制器的操作实例化DbContext而不是通过使用DI传递DbContext是否有问题?

Since each instance of DbContext is isolated per request, is there anything wrong with instantiating the DbContext directly from the controller's action instead of passing it through using DI?

推荐答案

您可以/应该使用抽象工厂来创建DbContext

You can/should use an abstract factory to create the DbContext

public interface IDbContextFactory
{
    ApplicationContext Create();
}

public class DbContextFactory() : IDbContextFactory, IDisposable
{
    private ApplicationContext context;
    private bool disposing;

    public DbContextFactory(/* other dependencies here */)
    {
    }

    public ApplicationContext Create(string tenantId) 
    {
        if(this.context==null) 
        {
            // and the connection string and replace the database name in it
            // with the tenantId or whatever means you have to determine
            // which database to access
            string connectionString = ...;

            var dbContextBuilder = new DbContextOptionsBuilder();
            dbContextBuilder.UseSqlServer(connectionString);

            this.context = new ApplicationContext(dbContextBuilder);
        }

        return this.context;
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing){
        if (disposing){
            disposing?.Dispose();
        }
    }
}

注册

services.AddScoped<IDbContextFactory, DbContextFactory>();

并按照以下说明在您的控制器中使用

and use it in your controllers as following

public class MyController : Controller
{
    private readonly IDbContextFactory contextFactory;

    public MyController(IMyContextFactory contextFactory)
    {
        this.contextFactory = contextFactory;
    }

    public Task<IActionResult> GetSomeData(string tenantId)
    {
        var context = contextFactory.Create(tenantId);

        return Ok(await context.Data.Where(...).ToListAsync());
    }
}

这篇关于仅在调用控制器操作时才知道数据库名称时,注入DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆