在 ASP.Net 中实现多租户:设置数据库上下文
在此示例中,我使用 GUI 创建一个 .net 7 项目。请注意,为简单起见,我将在一个解决方案中创建一个项目。理想情况下,您需要根据自己的要求拥有 API、核心、基础架构等项目。我将为这些创建文件夹。
配置新项目
其他信息:
对于此博客,我们需要安装以下 nuget 包并进行必要的配置:
已安装的 nugget 软件包
由于我们没有创建多个项目,因此我们将使用文件夹来组织我们的代码。在项目中创建一个“Data”文件夹,另外两个文件夹 EntityConfigurations 和 Factories。
在“数据”文件夹中,创建 PlatformDbContext 和 IntraDbContext,如下所示:
public class PlatformDbContext : DbContext
{
private readonly IOptions<MyAppOptions> _configuration;
public DbSet<Tenant> Tenants { get; set; }
public PlatformDbContext(DbContextOptions\<PlatformDbContext> options, IOptions<MyAppOptions> configuration) : base(options)
{
_configuration = configuration;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Tenant>().ToTable("Tenants");
modelBuilder.Entity<Tenant>().HasIndex(x => x.Name).IsUnique(true);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var localConnection = _configuration.Value.PlatformConnectionString;
optionsBuilder.UseSqlServer(localConnection);
}
}public class TenantDbContext : DbContext
{
public DbSet\<Listing> Listings { get; set; }
public TenantDbContext(DbContextOptions\<TenantDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TenantDbContext).Assembly);
}
}
在新文件夹 [project]/Contracts/Data 中创建模型:
public class EntityBase
{
[Key]
public int Id { get; set; }
[Required]
public DateTime DateCreated { get; set; } = DateTime.UtcNow;
public DateTime? DateUpdated { get; set; } = null;
}
public class Tenant : EntityBase
{
[Required, StringLength(100)]
public string Name { get; set; } = null!;
[Required, StringLength(20)]
public string Code { get; set; } = null!;
[Required, StringLength(500)]
public string ConnectionString { get; set; } = null!;
}
public class Listing : EntityBase
{
[Required, StringLength(100)]
public string Name { get; set; } = null!;
[Required, StringLength(150)]
public string Slug { get; set; } = null!;
[Required, Column(TypeName = "decimal(18,2)")]
public decimal Price { get; set; }
}
...然后在 :Program.cs
using MultiTenancyDemo.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddDbContext<PlatformDbContext>();
builder.Services.AddDbContext<TenantDbContext>();
请记住创建“IEntityTypeConfiguration”实现来配置数据库表。
若要动态检索平台的连接字符串,请配置 .IOptions
首先,我们首先创建 options 类。您可以根据应用程序的需要扩展它以匹配文件: appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MyAppSettings": {
"PlatformConnectionString": "Server =.\\SQLExpress;Database=Platform;Trusted\_Connection=True;TrustServerCertificate=True;",
}
}
...然后是 options 类:
public class MyAppOptions
{
public string PlatformConnectionString { get; set; } = null!;
}
为了更好地组织我们的代码并整理文件,请在新文件夹 [project]/Extensions 中创建“ConfigurationServiceCollectionExtensions”:Program.cs
public static class ConfigurationServiceCollectionExtensions
{
public static IServiceCollection AddMyOptions(this IServiceCollection services)
{
services.AddOptions<MyAppOptions>().BindConfiguration("MyAppSettings");
return services;
}
}
...然后在 :Program.cs
using MultiTenancyDemo.Data;
using MultiTenancyDemo.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddMyOptions();
builder.Services.AddDbContext<PlatformDbContext>();
builder.Services.AddDbContext<TenantDbContext>();
对于我们来说,运行平台数据库的迁移应该没问题。
我们暂时无法为 TenantDatabase 运行迁移。请记住,我们需要知道连接字符串,该字符串(安全地)存储在 Tenants 表中。因此,让我们在服务器上创建数据库,然后运行迁移。
Add-Migration InitialMigration -Context PlatformDbContext
我们应该得到以下迁移:
public partial class InitialMigration : Migration
{
**///** **<inheritdoc />**
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Tenants",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Code = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
ConnectionString = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
DateCreated = table.Column<DateTime>(type: "datetime2", nullable: false),
DateUpdated = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Tenants", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Tenants_Name",
table: "Tenants",
column: "Name",
unique: true);
}
**///** **<inheritdoc />**
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Tenants");
}
}
..然后,我们应用迁移:
Update-Database -Context PlatformDbContext
在服务器上创建数据库
接下来我们需要做的是将租户添加到表中。我们应该使用平台的后端来做到这一点,该后端也应该创建子域,但这超出了这篇博文的范围。因此,让我们手动将其添加到数据库中。
注意:为简单起见,我们在此处存储连接字符串。在生产中,您需要确保此类敏感数据得到妥善保护,例如对其进行加密。
添加到数据库的租户记录
源代码获取:公众号回复消息【code:66935
】