1

I am working on an ASP.NET Core Web API application. My API will accept a country name as one of the input parameter from request body.

Due to nature of the application, we have country wise database with same schema. I have created DbContext for one of the databases and want to initialize the DbContext by the passing the connection string based on input request parameter value.

I have created factory method to return the needed database context based on the parameter passed to the factory method. However, the challenge I am facing is, while initializing the factory class as DI from controller, object of factory class is instantiated before the controller action is called. Hence, parameter value in factory method is empty.

How can I pass a parameter in runtime to initialize an object using dependency injection?

Here is the code...

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

}

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

    public virtual DbSet<Student> Students { get; set; }
}

public interface IDbContextFactory
{
    public MyDBContext GetDbContext(string
     connectionString);
}


public class DbContextFactory : IDbContextFactory
{
    public MyDBContext GetDbContext(string connectionString)
    {
        MyDBContext context = null;

        if (!string.IsNullOrWhiteSpace(connectionString))
        {
            DbContextOptionsBuilder<MyDBContext> _dbContextOptionsBuilder = new DbContextOptionsBuilder<MyDBContext>().UseSqlServer(connectionString);
            context = new MyDBContext(_dbContextOptionsBuilder.Options);
        }
        return context;
    }
}


public interface IRepository
{
    Student GetData();
}


public class Repository : IRepository
{
    private MyDBContext _context;
    public Repository(IDbContextFactory dbContextFactory)
    {
        // Here I need connection string based on input parameter (country) from request to dynamically generate country specific connection string
        string connectionString = string.Empty; 

        _context = dbContextFactory.GetDbContext(connectionString);
    }

    public Student GetData()
    {
       return _context.Students.FirstOrDefault();
    }
}



public interface IServiceAgent
{
    Student GetData();
}


public class ServiceAgent : IServiceAgent
{
    IRepository _repository;
    public ServiceAgent(IRepository repository)
    {
        _repository = repository;
    }

    public Student GetData()
    {
       return _repository.GetData();
    }
}


[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
    private readonly IServiceAgent _serviceAgent;

    public HomeController(IServiceAgent serviceAgent)
    {
        _serviceAgent = serviceAgent;
    }

    [HttpGet]
    public Student Get(string country)
    {
        return _serviceAgent.GetData();
    }
}


public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddScoped<IServiceAgent, ServiceAgent>();
        services.AddScoped<IRepository, Repository>();
        services.AddScoped<IDbContextFactory, DbContextFactory>();
        services.AddScoped<DetermineCountryFilter>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
Mousam
  • 205
  • 1
  • 3
  • 10
  • Can you post your code? – abdusco Jul 21 '21 at 06:07
  • 2
    Agree with abdusco, it is better to share the relate code to reproduce the problem. Besides, you could check this similar thread: [Create an EF Core DbContext at runtime based on request parameters](https://stackoverflow.com/questions/54760793/create-an-ef-core-dbcontext-at-runtime-based-on-request-parameters). – Zhi Lv Jul 21 '21 at 08:33
  • I have added a sample code. In Repository class constructor I am creating an object of my DbContext. However, that DbContext needs to point to country specific database where country will be passed in controller action. – Mousam Jul 21 '21 at 20:09
  • Here is [a thread](https://stackoverflow.com/questions/40836102/asp-net-core-change-ef-connection-string-when-user-logs-in) which using one dbcontext factory with multiple connection string, you could check it. Besides, you could also create multiple DBcontext based on the different connection string, then, according the key value to select DBContext, [like this](https://stackoverflow.com/questions/42616408/entity-framework-core-multiple-connection-strings-on-same-dbcontext). – Zhi Lv Jul 22 '21 at 08:51

0 Answers0