在 ASP.Net 中实现多租户:设置数据库上下文

作者:微信公众号:【架构师老卢】
2-2 16:21
29

概述:在 ASP.Net 中实现多租户:设置数据库上下文设置项目在此示例中,我使用 GUI 创建一个 .net 7 项目。请注意,为简单起见,我将在一个解决方案中创建一个项目。理想情况下,您需要根据自己的要求拥有 API、核心、基础架构等项目。我将为这些创建文件夹。配置新项目其他信息:安装 nuget 包对于此博客,我们需要安装以下 nuget 包并进行必要的配置:_Microsoft.EntityFrameworkCore:_这是使用 LINQ 处理数据库所需的核心实体框架包。DbContext_Microsoft.EntityFrameworkCore.Design:_Entity Framew

在 ASP.Net 中实现多租户:设置数据库上下文

设置项目

在此示例中,我使用 GUI 创建一个 .net 7 项目。请注意,为简单起见,我将在一个解决方案中创建一个项目。理想情况下,您需要根据自己的要求拥有 API、核心、基础架构等项目。我将为这些创建文件夹。

配置新项目

其他信息:

安装 nuget 包

对于此博客,我们需要安装以下 nuget 包并进行必要的配置:

  1. _Microsoft.EntityFrameworkCore:_这是使用 LINQ 处理数据库所需的核心实体框架包。DbContext
  2. _Microsoft.EntityFrameworkCore.Design:_Entity Framework Core 设计时操作(如迁移)需要。此包是使用命令的先决条件。dotnet ef
  3. _Microsoft.EntityFrameworkCore.SqlServer:_此包允许实体框架核心与 Microsoft SQL Server 一起使用。
  4. _Microsoft.Extensions.Configuration:_提供用于处理配置数据(如读取自和环境变量)所需的 API。appsettings.json
  5. _Microsoft.Extensions.Configuration.Json:_允许应用程序从 JSON 文件中读取配置设置,例如 .appsettings.json
  6. _Microsoft.Extensions.Configuration.EnvironmentVariables:_允许从环境变量中读取配置设置,这对于覆盖不同部署环境中的设置特别有用。
  7. _Microsoft.Extensions.Options:_允许使用模式,这是一种在应用程序中以强类型方式访问配置值的方法。IOptions
  8. AutoMapper_:_一个简化不同对象模型之间映射的库。它消除了对手动映射代码的需要,从而可以更轻松地在类型之间移动数据。

已安装的 nugget 软件包

定义 DbContexts

由于我们没有创建多个项目,因此我们将使用文件夹来组织我们的代码。在项目中创建一个“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

若要动态检索平台的连接字符串,请配置 .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

相关代码下载地址
重要提示!:取消关注公众号后将无法再启用回复功能,不支持解封!
第一步:微信扫码关键公众号“架构师老卢”
第二步:在公众号聊天框发送code:66935,如:code:66935 获取下载地址
第三步:恭喜你,快去下载你想要的资源吧
相关留言评论
昵称:
邮箱:
阅读排行