mirror of https://github.com/abpframework/abp.git
7 changed files with 168 additions and 3 deletions
@ -0,0 +1,10 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Data.MultiTenancy |
|||
{ |
|||
public interface ITenantConnectionStringStore |
|||
{ |
|||
[CanBeNull] |
|||
string GetConnectionStringOrNull([NotNull] string tenantId, [CanBeNull] string databaseName); |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Data.MultiTenancy |
|||
{ |
|||
//TODO: It would be better to use composition over inheritance on connection string resolve progress!
|
|||
//TODO: Create a replace service registration convention, instead of custom registration in AbpMultiTenancyModule?
|
|||
|
|||
[DisableConventionalRegistration] |
|||
public class MultiTenantConnectionStringResolver : DefaultConnectionStringResolver |
|||
{ |
|||
private readonly IMultiTenancyManager _multiTenancyManager; |
|||
private readonly ITenantConnectionStringStore _tenantConnectionStringStore; |
|||
|
|||
public MultiTenantConnectionStringResolver( |
|||
IOptions<DbConnectionOptions> options, |
|||
IMultiTenancyManager multiTenancyManager, |
|||
ITenantConnectionStringStore tenantConnectionStringStore) |
|||
: base(options) |
|||
{ |
|||
_multiTenancyManager = multiTenancyManager; |
|||
_tenantConnectionStringStore = tenantConnectionStringStore; |
|||
} |
|||
|
|||
public override string Resolve(string databaseName = null) |
|||
{ |
|||
var tenant = _multiTenancyManager.CurrentTenant; |
|||
if (tenant == null) |
|||
{ |
|||
return base.Resolve(databaseName); |
|||
} |
|||
|
|||
var connectionString = _tenantConnectionStringStore.GetConnectionStringOrNull(tenant.Id, databaseName); |
|||
if (connectionString == null) |
|||
{ |
|||
return base.Resolve(databaseName); |
|||
} |
|||
|
|||
return connectionString; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Data.MultiTenancy |
|||
{ |
|||
public sealed class NullTenantConnectionStringStore : ITenantConnectionStringStore, ISingletonDependency |
|||
{ |
|||
public string GetConnectionStringOrNull(string tenantId, string databaseName) |
|||
{ |
|||
//No tenant specific connection string by default
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,95 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Microsoft.Extensions.Options; |
|||
using Shouldly; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Data.MultiTenancy |
|||
{ |
|||
public class MultiTenantConnectionStringResolver_Tests : MultiTenancyTestBase |
|||
{ |
|||
private readonly IMultiTenancyManager _multiTenancyManager; |
|||
private readonly IConnectionStringResolver _connectionResolver; |
|||
|
|||
public MultiTenantConnectionStringResolver_Tests() |
|||
{ |
|||
_multiTenancyManager = ServiceProvider.GetRequiredService<IMultiTenancyManager>(); |
|||
|
|||
_connectionResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>(); |
|||
_connectionResolver.ShouldBeOfType<MultiTenantConnectionStringResolver>(); |
|||
} |
|||
|
|||
protected override void BeforeAddApplication(IServiceCollection services) |
|||
{ |
|||
services.Configure<DbConnectionOptions>(options => |
|||
{ |
|||
options.ConnectionStrings.Default = "default-value"; |
|||
options.ConnectionStrings["db1"] = "db1-default-value"; |
|||
options.ConnectionStrings["tenant1#Default"] = "tenant1-default-value"; |
|||
options.ConnectionStrings["tenant1#db1"] = "tenant1-db1-value"; |
|||
}); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
services.Replace(ServiceDescriptor.Transient<ITenantConnectionStringStore, MyTenantConnectionStringStore>()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void All_Tests() |
|||
{ |
|||
//No tenant in current context
|
|||
_connectionResolver.Resolve().ShouldBe("default-value"); |
|||
_connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); |
|||
|
|||
//Overrided connection strings for tenant1
|
|||
using (_multiTenancyManager.ChangeTenant(new TenantInfo("tenant1"))) |
|||
{ |
|||
_connectionResolver.Resolve().ShouldBe("tenant1-default-value"); |
|||
_connectionResolver.Resolve("db1").ShouldBe("tenant1-db1-value"); |
|||
} |
|||
|
|||
//No tenant in current context
|
|||
_connectionResolver.Resolve().ShouldBe("default-value"); |
|||
_connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); |
|||
|
|||
//Undefined connection strings for tenant2
|
|||
using (_multiTenancyManager.ChangeTenant(new TenantInfo("tenant2"))) |
|||
{ |
|||
_connectionResolver.Resolve().ShouldBe("default-value"); |
|||
_connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); |
|||
} |
|||
} |
|||
|
|||
public class MyTenantConnectionStringStore : ITenantConnectionStringStore |
|||
{ |
|||
private readonly IOptions<DbConnectionOptions> _options; |
|||
|
|||
public MyTenantConnectionStringStore(IOptions<DbConnectionOptions> options) |
|||
{ |
|||
_options = options; |
|||
} |
|||
|
|||
public string GetConnectionStringOrNull(string tenantId, string databaseName) |
|||
{ |
|||
if (databaseName != null) |
|||
{ |
|||
if (_options.Value.ConnectionStrings.ContainsKey(tenantId + "#" + databaseName)) |
|||
{ |
|||
return _options.Value.ConnectionStrings[tenantId + "#" + databaseName]; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (_options.Value.ConnectionStrings.ContainsKey(tenantId + "#Default")) |
|||
{ |
|||
return _options.Value.ConnectionStrings[tenantId + "#Default"]; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue