标签:todo har cep cookie tab ret default vat get
1、AbpMultiTenancyModule模块,DefaultTenantStoreOptions存储配置租户信息TenantConfiguration数组,每个租户包括Guid,Name,ConnectionStrings
[DependsOn( typeof(AbpDataModule), typeof(AbpSecurityModule) )] public class AbpMultiTenancyModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); Configure<DefaultTenantStoreOptions>(configuration); } } }
比如,如何从配置或ITenantStore得到租户信息
services.Configure<DefaultTenantStoreOptions>(options => { options.Tenants = new[] { new TenantConfiguration(_tenant1Id, "tenant1") { ConnectionStrings = { { ConnectionStrings.DefaultConnectionStringName, "tenant1-default-value"}, {"db1", "tenant1-db1-value"} } }, new TenantConfiguration(_tenant2Id, "tenant2") }; });
services.Configure<DbConnectionOptions>(options => { options.ConnectionStrings.Default = "default-value"; options.ConnectionStrings["db1"] = "db1-default-value"; });
另外关注MultiTenancyOptions
public class MultiTenancyOptions { /// <summary> /// A central point to enable/disable multi-tenancy. /// Default: false. /// </summary> public bool IsEnabled { get; set; } /// <summary> /// Database style for tenants. /// Default: <see cref="MultiTenancyDatabaseStyle.Hybrid"/>. /// </summary> public MultiTenancyDatabaseStyle DatabaseStyle { get; set; } = MultiTenancyDatabaseStyle.Hybrid; }
2、ICurrentTenant 当前租户,依赖ICurrentTenantAccessor来确定,关注Change方法IDisposable Change(Guid? id, string name = null);
public IDisposable Change(Guid? id, string name = null) { return SetCurrent(id, name); } private IDisposable SetCurrent(Guid? tenantId, string name = null) { var parentScope = _currentTenantAccessor.Current; _currentTenantAccessor.Current = new BasicTenantInfo(tenantId, name); return new DisposeAction(() => { _currentTenantAccessor.Current = parentScope; }); }
3、ICurrentTenantAccessor,依赖BasicTenantInfo信息来确定(null值使用host,不是null值使用租户信息),TenantId是指示是否赋值,AsyncLocal<BasicTenantInfo>
4、ITenantResolver,这里有一个传递ITenantResolveContext ,传递入IServiceProvider,通过ITenantResolveContributor的实现来确定当前租户TenantResolveResult,ITenantResolveContributor,从GetTenantIdOrNameFromHttpContextOrNull实现方法在Volo.Abp.AspNetCore.MultiTenancy模块,获取租户的Id和名称有五种方法,Cookie,Domain,Header,QueryString,Route,实现在模块Volo.Abp.AspNetCore.MultiTenancy里面
public interface ITenantResolveContributor
{
string Name { get; }
void Resolve(ITenantResolveContext context);
}
public abstract class TenantResolveContributorBase : ITenantResolveContributor
{
public abstract string Name { get; }
//TODO: We can make this async
public abstract void Resolve(ITenantResolveContext context);
}
public abstract class HttpTenantResolveContributorBase : TenantResolveContributorBase
{
。。。。
protected abstract string GetTenantIdOrNameFromHttpContextOrNull([NotNull] ITenantResolveContext context, [NotNull] HttpContext httpContext);
。。。。
}
[DependsOn( typeof(AbpMultiTenancyModule), typeof(AbpAspNetCoreModule) )] public class AbpAspNetCoreMultiTenancyModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { Configure<TenantResolveOptions>(options => { options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); options.TenantResolvers.Add(new RouteTenantResolveContributor()); options.TenantResolvers.Add(new HeaderTenantResolveContributor()); options.TenantResolvers.Add(new CookieTenantResolveContributor()); }); } }
public const string DefaultTenantKey = "__tenant";
其实现TenantResolver,通过遍历TenantResolveOptions下面的List<ITenantResolveContributor> TenantResolvers,获取得TenantIdOrName
6、ITenantStore,查找租户
[Dependency(TryRegister = true)] public class DefaultTenantStore : ITenantStore, ITransientDependency { private readonly DefaultTenantStoreOptions _options; public DefaultTenantStore(IOptionsSnapshot<DefaultTenantStoreOptions> options) { _options = options.Value; } public Task<TenantConfiguration> FindAsync(string name) { return Task.FromResult(_options.Tenants?.FirstOrDefault(t => t.Name == name)); } public Task<TenantConfiguration> FindAsync(Guid id) { return Task.FromResult(_options.Tenants?.FirstOrDefault(t => t.Id == id)); } }
8、IConnectionStringResolver,解决连接字符串,MultiTenantConnectionStringResolver是替换实现服务, _connectionResolver.ShouldBeOfType<MultiTenantConnectionStringResolver>();
有实现如何获取字符串,包括从 ITenantStore查到TenantConfiguration或DbConnectionOptions或DefaultTenantStoreOptions配置文件
No tenant in current context:默认DbConnectionOptions
Overrided connection strings for tenant1:对应租户DefaultTenantStoreOptions
Undefined connection strings for tenant2:没有对应租户字符串使用默认字符串
public override string Resolve(string connectionStringName = null) { //No current tenant, fallback to default logic if (_currentTenant.Id == null) { return base.Resolve(connectionStringName); } using (var serviceScope = _serviceProvider.CreateScope()) { var tenantStore = serviceScope .ServiceProvider .GetRequiredService<ITenantStore>(); //租户存储获取,tenant-management进行管理 var tenant = AsyncHelper.RunSync(() => tenantStore.FindAsync(_currentTenant.Id.Value)); //TODO: Can we avoid from RunSync? // 当前租户没有连接字符串,则返回默认连接字符串 if (tenant?.ConnectionStrings == null) { return base.Resolve(connectionStringName); } //Requesting default connection string if (connectionStringName == null) { return tenant.ConnectionStrings.Default ?? Options.ConnectionStrings.Default; } //Requesting specific connection string var connString = tenant.ConnectionStrings.GetOrDefault(connectionStringName); if (connString != null) { return connString; } /* Requested a specific connection string, but it‘s not specified for the tenant. * - If it‘s specified in options, use it. * - If not, use tenant‘s default conn string. */ var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName); if (connStringInOptions != null) { return connStringInOptions; } return tenant.ConnectionStrings.Default ?? Options.ConnectionStrings.Default; } }
9、多租户的中间件
public async Task Invoke(HttpContext httpContext) { //实现是遍历Cookie,Domain,Header,QueryString,Route不同ITenantResolveContributor //,获取Tenant的ID和Name var resolveResult = _tenantResolver.ResolveTenantIdOrName(); _tenantResolveResultAccessor.Result = resolveResult; //获取配置文件,包括字符串 TenantConfiguration tenant = null; if (resolveResult.TenantIdOrName != null) { tenant = await FindTenantAsync(resolveResult.TenantIdOrName); if (tenant == null) { //TODO: A better exception? throw new AbpException( "There is no tenant with given tenant id or name: " + resolveResult.TenantIdOrName ); } } //设置为当前租户 using (_currentTenant.Change(tenant?.Id, tenant?.Name)) { await _next(httpContext); } }
标签:todo har cep cookie tab ret default vat get
原文地址:https://www.cnblogs.com/cloudsu/p/11169211.html