在ASP.NET Core中如何支持每个租户数据存储策略的数据库
在ASP.NET Core上实施每个租户策略的数据库
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址
本博文翻译自:
http://gunnarpeipman.com/2017/08/database-per-tenant/
让我们继续使用ASP.NET Core web应用程序中的多租户,并关注每个租户都有自己的数据库的解决方案。它不仅仅是关于数据库的——可以有更多的服务,每个租户都有自己的实例。它使这里提供的解决方案可以轻松地扩展到除SQL Server或其他任何关系数据库之外的其他服务。
以往的工作
在讨论解决方案之前,我建议先浏览一下我以前的文章,内容包括ASP.NET Core web应用程序中的多租户的一些方面:
- [Entity Framework Core 2.0 全局查询过滤器](http://www.cnblogs.com/chen-jie/p/ef-core-global-query-filters.html"Global query filters in Entity Framework Core 2.0")
- 在 ASP.NET Core 中执行租户服务
注意! 本文中的代码建立在上述文章的代码之上。
将数据库连接字符串移动到租户配置
这里的问题是如何动态决定使用哪个连接字符串,以及如何使用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应用程序中支持更复杂的场景变得非常容易。这篇博文关注的是多租户的一个方面——如何支持每个租户数据存储策略的数据库。如果需要的话,这个模型也可以扩展到更多的设置。
欢迎转载,转载请注明翻译原文出处(本文章),原文出处(原博客地址),然后谢谢观看
如果觉得我的翻译对您有帮助,请点击推荐支持:)
在ASP.NET Core中如何支持每个租户数据存储策略的数据库的更多相关文章
- 在ASP.NET Core中使用Apworks快速开发数据服务
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支 ...
- 汇总:ASP.NET Core中HttpContext获取传参数据,有哪些方式
一.原生方式: 1.POST(以ajax请求为案例,教大家用法) $.ajax({ type: "post", dataType: "json", cache: ...
- gRPC在 ASP.NET Core 中应用学习(二)
前言: 上一篇文章中简单的对gRPC进行了简单了解,并实现了gRPC在ASP.NET Core中服务实现.客户端调用:那么本篇继续对gRPC的4中服务方法定义.其他使用注意点进一步了解学习 一.gRP ...
- ASP.NET Core中返回 json 数据首字母大小写问题
ASP.NET Core中返回 json 数据首字母大小写问题 在asp.net core中使用ajax请求动态绑定数据时遇到该问题 后台返回数据字段首字母为定义的大写,返回的数据没有问题 但是在前台 ...
- 在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable ...
- ASP.NET Core 中的 WebSocket 支持(转自MSDN)
本文介绍 ASP.NET Core 中 WebSocket 的入门方法. WebSocket (RFC 6455) 是一个协议,支持通过 TCP 连接建立持久的双向信道. 它用于从快速实时通信中获益的 ...
- C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入
C# 嵌入dll 在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...
- [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢?
[.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢? 在ASP.NET Core应用程序中,接 ...
- 在ASP.NET Core中使用百度在线编辑器UEditor
在ASP.NET Core中使用百度在线编辑器UEditor 0x00 起因 最近需要一个在线编辑器,之前听人说过百度的UEditor不错,去官网下了一个.不过服务端只有ASP.NET版的,如果是为了 ...
随机推荐
- MySQL整数类型说明 int(5) vs int(7)
今天突然发现, mysql 中int(1)和tinyint(1)中的1只是指定显示长度,并不表示存储长度,只有字段指定zerofill时有用.位数限制基本没有意义. int(5) 这里的5表示的是 最 ...
- docker+tomcat 启动时非常慢原因之JRE /dev/random阻塞
docker+tomcat 启动时非常慢,一般正常启动几十秒的,发现docker+tomcat启动竟需要几分钟,不可思议 根本原因是 SecureRandom 这个 jre 的工具类的问题.那为什么 ...
- iOS 环信集成问题(连文档都不说明的坑。。)
首先,关于环信SDK的下载和一些依赖库的添加,在此我就不做详细介绍,(http://www.easemob.com/download/im)附上环信官网文档,可以看一下,上面都可以下载,也有相关配置介 ...
- [ASP.NET MVC]笔记(三) 成员资格、授权和安全性
阻止CSRF(跨站请求伪造) ASP.NET MVC提供了一个阻止CSRF攻击的好方法 在每个提交的表单中包含 @using (Html.BeginForm("Index", &q ...
- Go数组、切片、映射的原理--简明解析
数组.切片.映射是Golang的最重要的数据结构,下面是对这3种数据结构的一点个人总结: 一.数组 数组是切片和映射的基础数据结构. 数组是一个长度固定的数据类型,存储着一段具有相同数据类型元素的连续 ...
- [我所理解的REST] 2.REST用来干什么的?
笔者每当遇到一个新事物的想去了解的时候,总是会问上自己第一个问题,这个新事物是干什么用的?在解释我所理解的REST这个过程中也不例外,这篇博客我们先关注一下REST是干什么用的,然后后续再解释REST ...
- git和github的重要性
Git是一款免费.开源的分布式版本控制系统,github是全球最大的同性交友平台啊呸,说错了github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就 ...
- 个人总结-Alpha阶段
一.个人总结 经过几周的Alpha阶段,对于软件设计有了大概的认识,也深刻感觉到一款软件设计出来的不易,每款软件背后都是开发人员辛勤的汗水.在软件开发的过程中,也是会出现很多的问题,出现各种各样的bu ...
- Git和Github使用
什么是Git? Git 是一个快速.可扩展的分布式版本控制系统,它具有极为丰富的命令集,对内部系统提供了高级操作和完全访问. 版本控制 简单地说,就是将在本地开发的代码,定时推送到服务器.每一次修改, ...
- 团队作业8——第二次项目冲刺(Beta阶段)Day5--5.23
1.提供当天站立式会议照片一张 2.会议内容 讨论已完成的功能 对于界面,谈谈各自的看法 商定测试计划 用户需求进一步调研 3.工作安排 队员 今日任务 明日任务 贡献比 林燕 测试运行效果 根据测试 ...