在ASP.NET Core上实施每个租户策略的数据库

不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址

本博文翻译自:

http://gunnarpeipman.com/2017/08/database-per-tenant/

让我们继续使用ASP.NET Core web应用程序中的多租户,并关注每个租户都有自己的数据库的解决方案。它不仅仅是关于数据库的——可以有更多的服务,每个租户都有自己的实例。它使这里提供的解决方案可以轻松地扩展到除SQL Server或其他任何关系数据库之外的其他服务。

以往的工作

在讨论解决方案之前,我建议先浏览一下我以前的文章,内容包括ASP.NET Core web应用程序中的多租户的一些方面:

注意! 本文中的代码建立在上述文章的代码之上。

将数据库连接字符串移动到租户配置

这里的问题是如何动态决定使用哪个连接字符串,以及如何使用web应用程序配置未更改的方式使连接字符串可用。后者实际上是在我之前的多租户文章中解决的在 ASP.NET Core 中执行租户服务我建议使用我此篇文章中提到的BlobStorageTenantProvider

与前一篇文章不同的是,当租户使用不同的数据库时,在这些数据库中不需要租户id。不支持软删除的应用程序可以在使用本文建议的解决方案时使用经典的简单数据上下文。

新的租户类有一个额外的属性- DatabaseConnectionString,如这里所示。

public class Tenant
{
public int Id { get; set; }
public string Name { get; set; }
public string Host { get; set; }
public string DatabaseConnectionString { get; set; }
}

在Azure blob存储中保存的租户配置文件将是这样的。


[
{
"Id": 2,
"Name": "Local host",
"Host": "localhost:30172",
"DatabaseConnectionString": "<connection string 1>"
},
{
"Id": 3,
"Name": "Customer X",
"Host": "localhost:3331",
"DatabaseConnectionString": "<connection string 2>"
},
{
"Id": 4,
"Name": "Customer Y",
"Host": "localhost:33111",
"DatabaseConnectionString": "<connection string 3>"
}
]

返回租户而不是租户ID

由于租户可以定义更多的设置,所以开始处理租户类而不是租户ID。它将改变我的ITenantProvider接口和BlobStorageTenantProvider类。


public class BlobStorageTenantProvider : ITenantProvider
{
private static IList<Tenant> _tenants; private Tenant _tenant; public BlobStorageTenantProvider(IHttpContextAccessor accessor, IConfiguration conf)
{
if(_tenants == null)
{
LoadTenants(conf["StorageConnectionString"], conf["TenantsContainerName"], conf["TenantsBlobName"]);
} var host = accessor.HttpContext.Request.Host.Value;
var tenant = _tenants.FirstOrDefault(t => t.Host.ToLower() == host.ToLower());
if(tenant != null)
{
_tenant = tenant;
}
} private void LoadTenants(string connStr, string containerName, string blobName)
{
var storageAccount = CloudStorageAccount.Parse(connStr);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
var blob = container.GetBlobReference(blobName); blob.FetchAttributesAsync().GetAwaiter().GetResult(); var fileBytes = new byte[blob.Properties.Length]; using (var stream = blob.OpenReadAsync().GetAwaiter().GetResult())
using (var textReader = new StreamReader(stream))
using (var reader = new JsonTextReader(textReader))
{
_tenants = JsonSerializer.Create().Deserialize<List<Tenant>>(reader);
}
} public Tenant GetTenant()
{
return _tenant;
}
}

动态配置数据上下文

我想在这里,多租户应用程序不处理软删除。现在,为了使用正确的连接字符串,必须修改mult-tenant应用程序的默认数据上下文。


public class PlaylistContext : DbContext
{
private readonly Tenant _tenant; public DbSet<Playlist> Playlists { get; set; }
public DbSet<Song> Songs { get; set; } public PlaylistContext(DbContextOptions<PlaylistContext> options,
ITenantProvider tenantProvider)
: base(options)
{
_tenant = tenantProvider.GetTenant();
} protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_tenant.DatabaseConnectionString); base.OnConfiguring(optionsBuilder);
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Playlist>().HasKey(e => e.Id);
modelBuilder.Entity<Song>().HasKey(e => e.Id); base.OnModelCreating(modelBuilder);
}
}

在查看代码时,很容易看出没有多少代码,但它会产生大胆灵活的模型,去支持不同的租户策略。

结束

ASP.NET Core的依赖注入模型和Entity Framework Core的灵活性使得在ASP.NET Core web应用程序中支持更复杂的场景变得非常容易。这篇博文关注的是多租户的一个方面——如何支持每个租户数据存储策略的数据库。如果需要的话,这个模型也可以扩展到更多的设置。

欢迎转载,转载请注明翻译原文出处(本文章),原文出处(原博客地址),然后谢谢观看

如果觉得我的翻译对您有帮助,请点击推荐支持:)

最新文章

  1. Java 开发环境的搭建
  2. 关于thinkphp中的G方法使用
  3. iOS 开发者账号共用发布证书 (Distribution)问题
  4. 解决Github使用Fastly CDN而导致不能加载网页的方法 转自 沙丘:http://www.enkoo.net/fastly-cdn-in-gifhub.html
  5. [codevs1554]最佳课题选择
  6. ajax提交富文本,内容被截断,解决方法及思路
  7. Bitmap工具类
  8. [C#基础] 泛型
  9. iOS APP中Versions和build版本区别
  10. IE浏览器img不显示解决
  11. Python统计列表中的重复项出现的次数的方法
  12. 深度学习识别CIFAR10:pytorch训练LeNet、AlexNet、VGG19实现及比较(二)
  13. ISP PIPLINE (十三) CSM/CSC(color space matrix/convert)
  14. 2016vijos 6-1 松鼠聚会(LCA+卡空间)
  15. idea创建项目报错(Maven execution terminated abnormally (exit code 1) )解决方案
  16. 171. Excel Sheet Column Number (Math)
  17. VirtualBox中的快捷键
  18. Java的Spring内实现的mini版内存&quot;计数器&quot;功能
  19. SVM入门——线性分类器的求解,核函数
  20. 【jmeter】jmeter之-断言和检查点

热门文章

  1. HDU2732(KB11-K 最大流)
  2. Codeforces485D(SummerTrainingDay01-K)
  3. django-csrf攻击
  4. nodejs 爬虫模板 map&amp;array 数据模型
  5. AJAX的一些基础和AJAX的状态
  6. 【代码笔记】iOS-在Block中修改外部变量值的
  7. json 平面转树状 child [zhuan]
  8. Flutter开发中的几个常用函数
  9. 试试SQLServer 2014的内存优化表(转载)
  10. python基础学习7----编码与解码