Accessing the HttpContext from a DbContext
Sometimes it might be necessary to access the current HttpContext from inside a DbContext, namely, from inside the OnConfiguring or OnModelCreating methods. Why? Well, for once, because of multitenancy: we may want to be able to decide the connection string to use based on the requesting or the host's domain, the current user or some other request parameter. Here the internal dependency injection (Instance) can’t help, because it cannot be used inside these methods.
The only option we have is to inject the IHttpContextAccessor class through our DbContext class’ constructor, and, from it, get hold of the HttpContext.
First we need to register the IHttpContextAccessor service in ConfigureServices:
services.AddHttpContextAccessor();
We also need to register our context for dependency injection:
services.AddDbContext<MyContext>();
A context registered this way needs to have a special constructor that has a parameter of type DbContextOptions (or DbContextOptions<MyContext>), in our case, we just need to add an extra parameter of type IHttpContextAccessor:
public class MyContext : DbContext
{
public MyContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options)
{
this.HttpContextAccessor = httpContextAccessor;
}
protected IHttpContextAccessor HttpContextAccessor { get; }
}
Finally, when you need to access the HttpContext, you just need to retrieve it from the IHttpContextAccessor:
protected internal override void OnConfiguring(DbContextOptionsBuilder builder)
{
var httpContext = this.HttpContextAccessor.HttpContext;
var tenantService = httpContext.RequestServices.GetService<ITenantService>();
var connectionString = tenantService.GetConnectionString(httpContext);
builder.UseSqlServer(connectionString); base.OnConfiguring(builder);
}
Here the hypothetical ITenantService provides a method GetConnectionString that returns a connection string for the current HttpContext, and we use it with the SQL Server provider.
Hope you find this useful!