public void GetOrAddNamedOptionForCurrentTenantOnly(string name) { var ti = new TenantInfo("test-id-123", null, null, null, null); var tc = new MultiTenantContext(); tc.TenantInfo = ti; var tca = new TestMultiTenantContextAccessor(tc); var cache = new MultiTenantOptionsCache <InMemoryStoreOptions>(tca); var options = new InMemoryStoreOptions(); var options2 = new InMemoryStoreOptions(); // Add new options. var result = cache.GetOrAdd(name, () => options); Assert.Same(options, result); // Get the existing options if exists. result = cache.GetOrAdd(name, () => options2); Assert.NotSame(options2, result); // Confirm different tenant on same object is an add (ie it didn't exist there). ti.Id = "diff_id"; result = cache.GetOrAdd(name, () => options2); Assert.Same(options2, result); }
public static async Task Main(string[] args) { var host = CreateHostBuilder(args).Build(); // Set up the databases for the sample if needed. var env = host.Services.GetService <IWebHostEnvironment>(); if (env.EnvironmentName == "Development") { var config = host.Services.GetRequiredService <IConfiguration>(); var options = new InMemoryStoreOptions(); config.GetSection("Finbuckle:MultiTenant:InMemoryStore").Bind(options); foreach (var tenant in options.TenantConfigurations.Where(tc => tc.ConnectionString != null)) { using (var db = new ApplicationDbContext(new TenantInfo(null, null, null, tenant.ConnectionString, null))) { await db.Database.MigrateAsync(); } } using (var db = new ApplicationDbContext(new TenantInfo(null, null, null, options.DefaultConnectionString, null))) { await db.Database.MigrateAsync(); } } await host.RunAsync(); }
public void AddNamedOptionsForCurrentTenantOnlyOnAdd(string name) { var ti = new TenantInfo("test-id-123", null, null, null, null); var tc = new MultiTenantContext(); tc.TenantInfo = ti; var tca = new TestMultiTenantContextAccessor(tc); var cache = new MultiTenantOptionsCache <InMemoryStoreOptions>(tca); var options = new InMemoryStoreOptions(); // Add new options. var result = cache.TryAdd(name, options); Assert.True(result); // Fail adding options under same name. result = cache.TryAdd(name, options); Assert.False(result); // Change the tenant id and confirm options can be added again. ti.Id = "diff_id"; result = cache.TryAdd(name, options); Assert.True(result); }
public void HandleNullMultiTenantContextOnGetOrAdd() { var tca = new TestMultiTenantContextAccessor(null); var cache = new MultiTenantOptionsCache <InMemoryStoreOptions>(tca); var options = new InMemoryStoreOptions(); // Add new options, ensure no exception caused by null MultiTenantContext. var result = cache.GetOrAdd("", () => options); Assert.NotNull(result); }
/// <summary> /// Creates an InMemoryStore from configured InMemoryMultiTenantStoreOptions. /// </summary> private IMultiTenantStore InMemoryStoreFactory(Action <InMemoryStoreOptions> config, bool ignoreCase, ILogger <MultiTenantStoreWrapper <InMemoryStore> > logger) { if (config == null) { throw new ArgumentNullException(nameof(config)); } var options = new InMemoryStoreOptions(); config(options); var store = new MultiTenantStoreWrapper <InMemoryStore>(new InMemoryStore(ignoreCase), logger); try { foreach (var tenantConfig in options.TenantConfigurations ?? new InMemoryStoreOptions.TenantConfiguration[0]) { if (string.IsNullOrWhiteSpace(tenantConfig.Id) || string.IsNullOrWhiteSpace(tenantConfig.Identifier)) { throw new MultiTenantException("Tenant Id and Identifer cannot be null or whitespace."); } var tenantInfo = new TenantInfo(tenantConfig.Id, tenantConfig.Identifier, tenantConfig.Name, tenantConfig.ConnectionString ?? options.DefaultConnectionString, null); foreach (var item in tenantConfig.Items ?? new Dictionary <string, string>()) { tenantInfo.Items.Add(item.Key, item.Value); } if (!store.TryAddAsync(tenantInfo).Result) { throw new MultiTenantException($"Unable to add {tenantInfo.Identifier} is already configured."); } } } catch (Exception e) { throw new MultiTenantException ("Unable to add tenant to store.", e); } return(store); }
public void RemoveNamedOptionsForCurrentTenantOnly(string name) { var ti = new TenantInfo("test-id-123", null, null, null, null); var tc = new MultiTenantContext(); tc.TenantInfo = ti; var tca = new TestMultiTenantContextAccessor(tc); var cache = new MultiTenantOptionsCache <InMemoryStoreOptions>(tca); var options = new InMemoryStoreOptions(); // Add new options. var result = cache.TryAdd(name, options); Assert.True(result); // Add under a different tenant. ti.Id = "diff_id"; result = cache.TryAdd(name, options); Assert.True(result); result = cache.TryAdd("diffname", options); Assert.True(result); // Remove named options for current tenant. result = cache.TryRemove(name); Assert.True(result); var tenantCache = (ConcurrentDictionary <string, IOptionsMonitorCache <InMemoryStoreOptions> >)cache.GetType(). GetField("map", BindingFlags.NonPublic | BindingFlags.Instance). GetValue(cache); dynamic tenantInternalCache = tenantCache[ti.Id].GetType().GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(tenantCache[ti.Id]); // Assert named options removed and other options on tenant left as-is. Assert.False(tenantInternalCache.Keys.Contains(name ?? "")); Assert.True(tenantInternalCache.Keys.Contains("diffname")); // Assert other tenant not affected. ti.Id = "test-id-123"; tenantInternalCache = tenantCache[ti.Id].GetType().GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(tenantCache[ti.Id]); Assert.True(tenantInternalCache.ContainsKey(name ?? "")); }
public void ClearOptionsForCurrentTenantOnly() { var ti = new TenantInfo("test-id-123", null, null, null, null); var tc = new MultiTenantContext(); tc.TenantInfo = ti; var tca = new TestMultiTenantContextAccessor(tc); var cache = new MultiTenantOptionsCache <InMemoryStoreOptions>(tca); var options = new InMemoryStoreOptions(); // Add new options. var result = cache.TryAdd("", options); Assert.True(result); // Add under a different tenant. ti.Id = "diff_id"; result = cache.TryAdd("", options); Assert.True(result); // Clear options on first tenant. ti.Id = "test-id-123"; cache.Clear(); // Assert options cleared on this tenant. var tenantCache = (ConcurrentDictionary <string, IOptionsMonitorCache <InMemoryStoreOptions> >)cache.GetType(). GetField("map", BindingFlags.NonPublic | BindingFlags.Instance). GetValue(cache); dynamic tenantInternalCache = tenantCache[ti.Id].GetType().GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(tenantCache[ti.Id]); Assert.True(tenantInternalCache.IsEmpty); // Assert options still exist on other tenant. ti.Id = "diff_id"; tenantInternalCache = tenantCache[ti.Id].GetType().GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(tenantCache[ti.Id]); Assert.False(tenantInternalCache.IsEmpty); }