C# 从BackgroundService创建DbContext租户时配置它
我有一个ASP.NET Core 3.1应用程序,它使用一个现有的Postgres数据库,其中每个租户都存储在一个单独的模式中。这在HTTP请求中运行良好,租户标识符存储在请求中,在我的DbContext中,我在C# 从BackgroundService创建DbContext租户时配置它,c#,postgresql,entity-framework-core,dbcontext,C#,Postgresql,Entity Framework Core,Dbcontext,我有一个ASP.NET Core 3.1应用程序,它使用一个现有的Postgres数据库,其中每个租户都存储在一个单独的模式中。这在HTTP请求中运行良好,租户标识符存储在请求中,在我的DbContext中,我在onconfigurang方法中有以下代码: if (this._httpContextAccessor.HttpContext?.Items["tenant"] != null) { string tenant = this._httpContextAccess
onconfigurang
方法中有以下代码:
if (this._httpContextAccessor.HttpContext?.Items["tenant"] != null)
{
string tenant = this._httpContextAccessor.HttpContext.Items["tenant"].ToString();
builder.SearchPath = tenant;
}
else
{
throw new InvalidOperationException("The defined tenant does not exist. Cannot create DB Context");
}
这将为当前请求调整到租户的Postgres搜索路径
我现在尝试添加一个也需要使用数据库的后台服务。我的后台服务使用IServiceProvider,我尝试按如下方式创建我的DbContext,但由于我使用了多租户实现,这显然不起作用:
using var scope = this.serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetService<MyDbContext>();
使用var scope=this.serviceProvider.CreateScope();
var context=scope.ServiceProvider.GetService();
后台服务不像HTTP请求那样有租户,它需要处理该方面本身,并生成具有不同租户的DBContext
我不知道如何调整我的上下文,以便创建具有不同租户的实例。或者这是否真的是我应该做的,或者是否有更好的方法来处理这个问题。我知道通过Postgres模式实现的多租户不是ASP.NET核心的典型案例,但这是我现在无法改变的
当我需要从HTTP请求和与特定租户不关联的后台服务中使用DbContext时,我如何也应该基于Postgres模式对租户使用DbContext(例如,通过租户循环在每个租户上执行作业)?一种解决方案是不要直接使用
HttpContext
获取租户ID。相反,创建一个可以控制并注入该ID的服务。该服务可以使用HttpContext
,但如果您告诉它,它将使用其他内容。例如:
(注意:所有这些都是手动输入的,没有经过测试,但应该让您了解它是如何工作的)
调整DbContext:
public class MyContext : DbContext
{
private readonly ITenantService _tenantService;
public MyContext(ITenantService tenantService)
{
_tenantService = tenantService;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var tenantId = _tenantService.GetTenantId();
if(string.IsNullOrEmpty(tenantId))
{
throw new InvalidOperationException("The defined tenant does not exist...");
}
builder.SearchPath = tenantId;
base.OnConfiguring(optionsBuilder);
}
}
将服务添加到DI容器:
services.AddScoped<ITenantService, TenantService>();
services.addScope();
并在后台服务中这样使用它:
using var scope = this.serviceProvider.CreateScope();
// This will be the same instance that the DbContext receives
var tenantService = scope.ServiceProvider.GetService<ITenantService>();
tenantService.OverrideTenantId = "whatever";
var context = scope.ServiceProvider.GetService<MyDbContext>();
使用var scope=this.serviceProvider.CreateScope();
//这将是DbContext接收的同一个实例
var tenantService=scope.ServiceProvider.GetService();
tenantService.OverrideTenantId=“无论什么”;
var context=scope.ServiceProvider.GetService();
请注意,如果需要切换到其他租户,则可能需要创建新的
DbContext
和作用域。不要使用HttpContext
获取租户ID,而是创建一个可以控制的服务。该服务可以使用HttpContext
,但如果您告诉它,它将使用其他内容。我认为您应该使用单一模式和复合键管理多租户系统,每个表都有租户ID。谢谢,这似乎可行。我缺少的部分是如何构造一个服务,以便修改租户并将该版本的租户服务注入到我的BackgroundService中。
using var scope = this.serviceProvider.CreateScope();
// This will be the same instance that the DbContext receives
var tenantService = scope.ServiceProvider.GetService<ITenantService>();
tenantService.OverrideTenantId = "whatever";
var context = scope.ServiceProvider.GetService<MyDbContext>();