Skip to content

Instantly share code, notes, and snippets.

@danielplawgo
Created May 7, 2021 04:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielplawgo/350b581e04cc24d6d7b79f0d8837f27e to your computer and use it in GitHub Desktop.
Save danielplawgo/350b581e04cc24d6d7b79f0d8837f27e to your computer and use it in GitHub Desktop.
Multi Tenant - jedna baza danych per tenant
public class ConnectionStringBuilder : IConnectionStringBuilder
{
private readonly ITenantAccessService _tenantAccessService;
private readonly IConfiguration _configuration;
public ConnectionStringBuilder(ITenantAccessService tenantAccessService,
IConfiguration configuration)
{
_tenantAccessService = tenantAccessService;
_configuration = configuration;
}
public async Task<string> BuildAsync()
{
var defaultConnection = _configuration.GetConnectionString("DefaultConnection");
var tenant = await _tenantAccessService.GetTenantAsync();
if (tenant == null)
{
return defaultConnection;
}
var builder = new SqlConnectionStringBuilder(defaultConnection);
builder.InitialCatalog = tenant.Identifier;
return builder.ConnectionString;
}
}
public class DatabaseTenantStore : ITenantStore
{
private readonly TenantDataContext _db;
public DatabaseTenantStore(TenantDataContext db)
{
_db = db;
}
public async Task<Tenant> GetTenantAsync(string identifier)
{
if (string.IsNullOrEmpty(identifier))
{
return null;
}
return await _db.Tenants.FirstOrDefaultAsync(t => t.Identifier.ToLower() == identifier.ToLower());
}
}
public interface IConnectionStringBuilder
{
Task<string> BuildAsync();
}
public interface ITenantAccessService
{
Task<Tenant> GetTenantAsync();
}
public interface ITenantStore
{
Task<Tenant> GetTenantAsync(string identifier);
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TenantDataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<ApplicationDbContext>((s, options) =>
options.UseSqlServer(s.GetRequiredService<IConnectionStringBuilder>().BuildAsync().Result));
//inne rejestracje
}
}
public class Tenant
{
public Guid Id { get; set; }
public string Identifier { get; set; }
}
public class TenantAccessService : ITenantAccessService
{
private readonly ITenantResolutionStrategy _tenantResolutionStrategy;
private readonly ITenantStore _tenantStore;
private Tenant _currentTenant;
public TenantAccessService(ITenantResolutionStrategy tenantResolutionStrategy, ITenantStore tenantStore)
{
_tenantResolutionStrategy = tenantResolutionStrategy;
_tenantStore = tenantStore;
}
public async Task<Tenant> GetTenantAsync()
{
if (_currentTenant != null)
{
return _currentTenant;
}
var tenantIdentifier = await _tenantResolutionStrategy.GetTenantIdentifierAsync();
_currentTenant = await _tenantStore.GetTenantAsync(tenantIdentifier);
return _currentTenant;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment