[英]Need a way to get the current request URL to configure the database context in multi-tenant application
I am migrating a web app from asp.net mvc to .net core (.net 5), and this has got me stuck.我正在将 web 应用程序从 asp.net mvc 迁移到 .net 核心(.net 5),这让我陷入困境。 The site is configured in IIS to accept request from multiple URLs like site1.example.com and site2.example.com.该站点在 IIS 中配置为接受来自多个 URL 的请求,例如 site1.example.com 和 site2.example.com。 Each site has its own database, accessed through entity framework core.每个站点都有自己的数据库,通过实体框架核心访问。
In the old .net framework, I was able to use one of the events in the global.asax.cs to parse the incoming request URL and lookup the correct tenant database from a configuration file.在旧的 .net 框架中,我能够使用 global.asax.cs 中的事件之一来解析传入的请求 URL 并从配置文件中查找正确的租户数据库。 I'm trying to set up something similar in asp.net core mvc.我正在尝试在 asp.net 核心 mvc 中设置类似的东西。
Here's the relevant part of my ConfigureServices method in the startup.cs这是我在 startup.cs 中的 ConfigureServices 方法的相关部分
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<ITenantIdentifier, UrlTenantIdentifier>();
services.AddDbContext<myDbContext>((serviceProvider, dbContextBuilder) =>
{
var tenantIdentifier = serviceProvider.GetRequiredService<ITenantIdentifier>();
var connectionString = Configuration.GetConnectionString(tenantIdentifier.GetCurrentTenantId() + "myDataModel");
dbContextBuilder.UseSqlServer(connectionString);
}, ServiceLifetime.Scoped);
//other services configured below...
}
Then the tenant identifier looks like this:然后租户标识符如下所示:
public interface ITenantIdentifier
{
string GetCurrentTenantId();
}
public class UrlTenantIdentifier : ITenantIdentifier
{
readonly IHttpContextAccessor _httpContextAccessor;
readonly ILogger<UrlTenantIdentifier> _logger;
public UrlTenantIdentifier(IHttpContextAccessor httpContextAccessor, ILogger<UrlTenantIdentifier> logger)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public string GetCurrentTenantId()
{
//_httpContextAccessor is null here
//logic below for parsing URL and finding if we're site1 or site2
}
}
Is there a correct way of doing this now that I'm not aware of?现在我不知道有正确的方法吗? How can I set up the entity framework database context for dependency injection when I don't know the connection string key until runtime?当我直到运行时才知道连接字符串键时,如何为依赖注入设置实体框架数据库上下文? Am I going to be stuck configuring separate sites and virtual directories in IIS?我会不会在 IIS 中配置单独的站点和虚拟目录?
Refactor the DbContext
to override the OnConfiguring
member.重构DbContext
以覆盖OnConfiguring
成员。 Inject configuration and context accessor and perform configuration there.注入配置和上下文访问器并在那里执行配置。
public class myDbContext : DbContext {
private readonly ITenantIdentifier tenantIdentifier;
private readonly IConfiguration configuration;
public myDbContext(IConfiguration configuration, ITenantIdentifier tenantIdentifier) {
this.configuration = configuration;
this.tenantIdentifier = tenantIdentifier;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
var connectionString = configuration
.GetConnectionString(tenantIdentifier.GetCurrentTenantId() + "myDataModel");
optionsBuilder.UseSqlServer(connectionString);
}
}
Trying to access the request context at the time the DbContext
is being created/initialized is too early in the request flow to get access to the desired information.在创建/初始化DbContext
时尝试访问请求上下文在请求流中为时过早,无法访问所需的信息。 It needs to happen after the context has already been initialized and injected.它需要在上下文已经初始化和注入之后发生。
public void ConfigureServices(IServiceCollection services)
services.AddHttpContextAccessor();
services.AddSingleton<ITenantIdentifier, UrlTenantIdentifier>();
services.AddDbContext<myDbContext>(); //Simplified since configuration is internal
//other services configured below...
}
Reference DbContext Lifetime, Configuration, and Initialization参考DbContext 生命周期、配置和初始化
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.