1

I am using .Net Core, using the built-in dependency injection. In my login screen, I need the user to also choose a departmental database - we have different databases with the same structure to use the same application with different data. However, I can't figure out how to add/modify the dbContext that late. Startup.cs has the DI, but I don't know which connection string to read from the config until the user has chosen the department. It is a small database, and the company is not concerned about the management of the duplicate databases.

How can I add the service late

services.AddDbContext<my_accountingContext>(options =>
options.UseMySQL(Configuration.GetConnectionString("CorrectDepartmentConfig")));

when I actually know what CorrectDepartmentConfig is?

Or, if that can't be done, how can I do a smelly change of the my_accountingContext after Startup.cs?

2

2 Answers 2

2

You can use an implementation factory overload of IServiceCollection in ConfigureServices method form Startup class:

//First register a custom made db context provider
services.AddTransient<ApplicationDbContextFactory>();
//Then use implementation factory to get the one you need
services.AddTransient(provider => provider.GetService<ApplicationDbContextFactory>().CreateApplicationDbContext());

The implementation of CreateApplicationDbContext depends on your specific needs, but a base implementation should look like the following:

public ApplicationDbContext CreateApplicationDbContext(){
  //TODO Something clever to create correct ApplicationDbContext with ConnectionString you need.
} 

After this implementation, you can inject the correct ApplicationDbContext in your controller, action...

public MyController(ApplicationDbContext dbContext)
{
    _dbContext = dbContext;
}

public IActionResult([FromServices] ApplicationDbContext dbContext){
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can always set the connection string from inside the protected OnConfiguring method. You can get access to the IConfiguration instance from there (the DbContext class has a service locator, Instance property), retrieve the connection string, and then call UseMySql extension method with the appropriate connection.

Something like this:

protected virtual void OnConfiguring(DbContextOptionsBuilder builder)
{
    var configuration = (this as IInfrastructure<IServiceProvider>).GetService<IConfiguration>();
    var connectionString = configuration.GetConnectionString("<name>");
    builder.UseMySql(connectionString);
    base.OnConfiguring(builder);
}

For the strongly-typed version of GetService do not forget to reference namespace Microsoft.Extensions.DependencyInjection.

4 Comments

This looks like it will work, thanks. But I'm having trouble with this.Instance.GetService - "'my_accountingContext' does not contain a definition for 'Instance' and no accessible extension method 'Instance' accepting a first argument of type 'rev_accountingContext' could be found (are you missing a using directive or an assembly reference?)". I have the using and the assembly reference for DependencyInjection.
See my edit. The Instance property comes from IInfrastructure<IServiceProvider>.
Thank you. Now, when attempting to execute "var configuration = ...", it complains that I'm using something while I'm attempting to configure it. 'An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.' What did I do wrong? Thanks!
You are not doing anything wrong, but there is a problem with my solution, as you just noticed. I think that the best way would be to pass an instance of IConfiguration to the DbContext-derived class through a factory method, as in the solution described below, and then store it and use it on the OnConfiguring method, rather than accessing the Instance property.

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.