Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从BackgroundService创建DbContext租户时配置它_C#_Postgresql_Entity Framework Core_Dbcontext - Fatal编程技术网

C# 从BackgroundService创建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

我有一个ASP.NET Core 3.1应用程序,它使用一个现有的Postgres数据库,其中每个租户都存储在一个单独的模式中。这在HTTP请求中运行良好,租户标识符存储在请求中,在我的DbContext中,我在
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>();