多租户框架案例
概念
多租户软件架构就是在同一个系统实例上运行不同用户,能做到应用程序共享,服务自治,并且还能做到数据互相隔离的软件架构思想。
需求
公司有多个集群需要访问配置中心项目,不同集群访问到的数据可能不同,所以每个租户一个独立的数据库,但是共用一个配置中心项目。
开始
解析租户信息
可以通过域名、URL、Header等方式解析租户信息
///
/// 解析租户信息
///
public interface ITenantResolver
{
Task GetIdentifierAsync();
}
DefaultHeaderTenantResolver:
public class DefaultHeaderTenantResolver : ITenantResolver
{
private readonly IHttpContextAccessor _accessor;
public DefaultHeaderTenantResolver(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public async Task GetIdentifierAsync()
{
string identifier = _accessor.HttpContext.Request.Headers["Identifier"];
if (string.IsNullOrWhiteSpace(identifier))
{
throw new System.Exception("Identifier不能为空");
}
return await Task.FromResult(identifier);
}
}
租户信息体基类
public class TenantInfoBase
{
///
/// 租户标识
///
public string Identifier { get; set; }
///
/// 数据库类型
///
public string DBType { get; set; }
///
/// 数据库连接字符串
///
public string ConnectionString { get; set; }
}
存储租户信息
///
/// 存储租户信息
///
///
public interface ITenantStore
{
///
/// 获取多租户信息
///
///
///
Task GetTenantAsync(string identifier);
///
/// 获取全部多租户信息
///
///
Task> GetTenantsAsync();
}
ITenantService
///
/// 多租户对外服务(外观模式)
///
///
public interface ITenantService where TTenant : TenantInfoBase
{
///
/// 异步获取当前请求租户信息
///
///
Task GetTenantAsync();
///
/// 获取全部多租户信息
///
///
Task> GetTenantsAsync();
}
public class TenantService : ITenantService
{
private readonly ITenantResolver _tenantResolver;
private readonly ITenantStore _tenantStore;
public TenantService(ITenantResolver tenantResolver, ITenantStore tenantStore)
{
_tenantResolver = tenantResolver;
_tenantStore = tenantStore;
}
public async Task GetTenantAsync()
{
var identifier = _tenantResolver.GetIdentifierAsync().Result;
return await _tenantStore.GetTenantAsync(identifier);
}
public async Task> GetTenantsAsync()
{
return (await _tenantStore.GetTenantsAsync()).ToList();
}
}
public class TenantBuilder where TTenant : TenantInfoBase
{
private readonly IServiceCollection _services;
public TenantBuilder(IServiceCollection services)
{
_services = services;
}
public TenantBuilder WithResolver(ServiceLifetime lifetime = ServiceLifetime.Transient) where TResolver : ITenantResolver
{
_services.TryAddSingleton();
_services.Add(new ServiceDescriptor(typeof(ITenantResolver), typeof(TResolver), lifetime));
return this;
}
public TenantBuilder WithStore(ServiceLifetime lifetime = ServiceLifetime.Transient)
{
_services.Add(new ServiceDescriptor(typeof(ITenantStore), typeof(TStore), lifetime));
return this;
}
}
public static class ServiceCollectionExtensions
{
public static TenantBuilder AddMultiTenant(this IServiceCollection services) where TTenant : TenantInfoBase
{
services.AddTransient(typeof(ITenantService), typeof(TenantService));
return new TenantBuilder(services);
}
}
参考: