我们尝试了本文来实现基于数据库的租户提供程序-https://www.codingame.com/playgrounds/5440/multi-tenant-asp-net-core-2---implementing-database-based-tenant-provider ...,它有2个数据库上下文ApplicationDbContext和MultiTenantDbContext。
我们设法为ApplicationDbContext做add-migration init and update-database
,但是我们不能不能为MultiTenantDbContext做第二个……并且它一直说对象引用的问题未设置为与`var host = accessor.HttpContext.Request.Host.Value;相关的对象;在下面的/Models/Tenant.cs上。
我的第二个问题,我不明白为什么这个DatabaseTenantProvider类在MultiTenantDbContext的add-migration init中执行?!?!
有什么想法吗?
代码如下:
/Models/Tenant.cs:
using AthlosifyCore.Data;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace AthlosifyCore.Models
{
public class Tenant
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string HostName { get; set; }
}
public interface ITenantProvider
{
Guid GetTenantId();
}
public class DatabaseTenantProvider : ITenantProvider
{
private Guid _tenantId;
public DatabaseTenantProvider(ApplicationDbContext context, IHttpContextAccessor accessor)
{
var host = accessor.HttpContext.Request.Host.Value;
context.AddSampleData();
// This is for real life cases
//_tenantId = context.Tenants.First(t => t.HostName == host).Id;
_tenantId = context.Tenants.First(t => t.HostName == "imaginary.example.com").Id;
}
public Guid GetTenantId()
{
return _tenantId;
}
}
}
/Data/ApplicationDbContext.cs:
using System;
using System.Collections.Generic;
using System.Text;
using AthlosifyCore.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace AthlosifyCore.Data
{
public class ApplicationDbContext : IdentityDbContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
public DbSet<Tenant> Tenants { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options,
IHttpContextAccessor httpContextAccessor)
: base(options)
{
_httpContextAccessor = httpContextAccessor;
}
public void AddSampleData()
{
Tenants.Add(new Tenant
{
Id = MultitenantDbContext.Tenant1Id,
Name = "Imaginary corp.",
HostName = "imaginary.example.com"
});
Tenants.Add(new Tenant
{
Id = MultitenantDbContext.Tenant2Id,
Name = "The Very Big corp.",
HostName = "big.example.com"
});
SaveChanges();
}
}
}
/Data/MultitenantDbContext.cs:
using AthlosifyCore.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AthlosifyCore.Data
{
public class MultitenantDbContext : DbContext
{
public static Guid Tenant1Id = Guid.Parse("51aab199-1482-4f0d-8ff1-5ca0e7bc525a");
public static Guid Tenant2Id = Guid.Parse("ae4e21fa-57cb-4733-b971-fdd14c4c667e");
public DbSet<Person> People { get; set; }
private ITenantProvider _tenantProvider;
public MultitenantDbContext(DbContextOptions<MultitenantDbContext> options,
ITenantProvider tenantProvider) : base(options)
{
_tenantProvider = tenantProvider;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>().HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId());
}
public void AddSampleData()
{
People.Add(new Person
{
Id = Guid.Parse("79865406-e01b-422f-bd09-92e116a0664a"),
TenantId = Tenant1Id,
FirstName = "Gunnar",
LastName = "Peipman"
});
People.Add(new Person
{
Id = Guid.Parse("d5674750-7f6b-43b9-b91b-d27b7ac13572"),
TenantId = Tenant2Id,
FirstName = "John",
LastName = "Doe"
});
People.Add(new Person
{
Id = Guid.Parse("e41446f9-c779-4ff6-b3e5-752a3dad97bb"),
TenantId = Tenant1Id,
FirstName = "Mary",
LastName = "Jones"
});
SaveChanges();
}
}
}
答案 0 :(得分:0)
我们不能为MultiTenantDbContext做第二个...并且它一直说对象引用的问题没有设置为与`var host = accessor.HttpContext.Request.Host.Value;相关的对象的实例;在下面的/Models/Tenant.cs上。
这是因为当您通过add-migration init
运行dotnet-tool时,根本没有HttpContext
。换句话说,accessor.HttpContext
目前为空,然后由于您正在访问Request
的{{1}}属性而失败。
要修复该错误,请更改以下代码:
null
此外,为避免多次添加样本并导致错误:
public DatabaseTenantProvider(TenantsDbContext context, IHttpContextAccessor accessor) { var host = accessor.HttpContext?.Request.Host.Value; // .... }
我们应该更改 Cannot insert duplicate key in object 'dbo.Tenants'. The duplicate key value is (51aab199-1482-4f0d-8ff1-5ca0e7bc525a).
类的AddSampleData()
方法:
TenantsDbContext
我的第二个问题,我不明白为什么这个DatabaseTenantProvider类在MultiTenantDbContext的add-migration init中执行?!?!
这是因为public class TenantsDbContext : DbContext
{
// ....
public void AddSampleData()
{
// add samples only if there's no record.
if(Tenants.Count()==0){
Tenants.Add(new Tenant
{
Id = MultitenantDbContext.Tenant1Id,
Name = "Imaginary corp.",
HostName = "imaginary.example.com"
});
Tenants.Add(new Tenant
{
Id = MultitenantDbContext.Tenant2Id,
Name = "The Very Big corp.",
HostName = "big.example.com"
});
SaveChanges();
}
}
}
已注册为DatabaseTenantProvider
服务的实现
ITenantProvider
services.AddTransient<ITenantProvider, DatabaseTenantProvider>()
类所必需的:
MultitenantDbContext
当EF Core调用public class MultitenantDbContext : DbContext
{
//...
// note we inject the `ITenantProvider` service here!
public MultitenantDbContext(DbContextOptions<MultitenantDbContext> options,
ITenantProvider tenantProvider) : base(options)
{
_tenantProvider = tenantProvider;
}
}
方法时,它将随后调用MultitenantDbContext.OnModelCreating()
服务(即ITenantProvider
类)以获取ID。