Inject DbContext when database name is only know when the controller action is called

让人想犯罪 __ 提交于 2019-12-08 04:43:19

问题


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).

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.

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?


回答1:


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();
        }
    }
}

Register it

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());
    }
}


来源:https://stackoverflow.com/questions/43016306/inject-dbcontext-when-database-name-is-only-know-when-the-controller-action-is-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!