Determine connection string by current tenant. Resolved #12.

pull/81/head
Halil İbrahim Kalkan 9 years ago
parent decd5f9ac0
commit 3061492973

@ -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;
}
}
}

@ -1,4 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Data;
using Volo.Abp.Data.MultiTenancy;
using Volo.Abp.Modularity;
namespace Volo.Abp.MultiTenancy
@ -7,6 +10,7 @@ namespace Volo.Abp.MultiTenancy
{
public override void ConfigureServices(IServiceCollection services)
{
services.Replace(ServiceDescriptor.Transient<IConnectionStringResolver, MultiTenantConnectionStringResolver>());
services.AddAssemblyOf<AbpMultiTenancyModule>();
}
}

@ -17,7 +17,7 @@ namespace Volo.Abp.TestBase
{
var services = CreateServiceCollection();
BeforeAppApplication(services);
BeforeAddApplication(services);
Application = services.AddApplication<TStartupModule>();
@ -33,7 +33,7 @@ namespace Volo.Abp.TestBase
return new ServiceCollection();
}
protected virtual void BeforeAppApplication(IServiceCollection services)
protected virtual void BeforeAddApplication(IServiceCollection services)
{
}

@ -14,7 +14,7 @@ namespace Volo.Abp.Data
_options = options.Value;
}
public string Resolve(string databaseName = null)
public virtual string Resolve(string databaseName = null)
{
//TODO: Override by tenant conn string
//TODO: Override by tenant module specific conn string

@ -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…
Cancel
Save