在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版的,如果是为了 ...
随机推荐
- postman 第4节 切换环境和设置读取变量(转)
postman提供了environment管理功能,想要在多个环境中测试,比如在测试环境.灰度环境.生产环境等,只需要用同样的接口,切换下环境即可,非常方便.具体步骤: 切换环境 1.点击界面右上角的 ...
- log4j与log4j.properties的配置
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt233 摘要: 一.配置步骤 1. 在应用程序中使用log4j 2. 把l ...
- 向eclipse的JavaWeb项目中导入jar包--备忘录
一: 在你所需的jar包网站下载对应的jar包.如org.apache.commons.lang.jar. 二:复制粘贴到该JavaWeb的WEB-INF目录下的lib目录下,如: 三:右键 ...
- Unity3D安装破解教程(以Unity5.3.4为例)(转)
Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏.建筑可视化.实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎.目 ...
- linux系统下C语言调用lapack ,blas库
在利用C语言编程,经常调用其他的软件包,其中lapack,blas库是最常用的两个库,这里讲下在linux系统下,C语言编程如何调用这两个库: 1.首先讲下blas库的调用,这里以两个向量内积函数为例 ...
- main方法和args参数
第一次接触java常常奇怪main方法和其参数有什么用.我们只知道main方法是程序入口,其实main方法同时也是一个可以手动调用的静态方法. 我们可以利用main方法写简单的一个递归程序 publi ...
- MySQL(四)--蠕虫复制、查询
1 蠕虫复制 蠕虫复制:从已有的数据中去获取数据,然后将数据又进行新增操作,数据成倍增加. 表创建高级操作:从已有创建新表(复制表结构) create table 表名 like 数据库.表名; 蠕虫 ...
- 团队作业4--第一次项目冲刺(Alpha版本)6
一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.对功能界面进行优化 2.对算法进行改进优化,提高运行速度 四.困难与问题 首先我们团队通过讨论,对功能界面进行了优化,让界 ...
- 【Beta阶段】第一次scrum meeting
Coding/OSChina 地址 1. 会议内容 学号 主要负责的方向 昨日任务 昨日任务完成进度 接下去要做 9 9 PM 博客编写,会议总结,代码整理 100% 准备下一次会议内容,并对已完成的 ...
- 201521123119《Java程序设计》第8周学习总结
1. 本周学习总结 2. 书面作业 Q1.List中指定元素的删除(题目4-1) Q1.1 实验总结 用split(" ")方法将list转化为字符串数组.要注意行中含有多个空格的 ...