Browse Source

Add `NormalizedName` property to `Tenant`.

Resolve #18394
pull/18426/head
maliming 3 years ago
parent
commit
712d547c4b
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 14
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs
  2. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs
  3. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs
  4. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs
  5. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs
  6. 6
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantNormalizer.cs
  7. 4
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantStore.cs
  8. 10
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs
  9. 11
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/UpperInvariantTenantNormalizer.cs
  10. 8
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/DefaultTenantStore.cs
  11. 7
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfigurationProvider.cs
  12. 3
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs
  13. 3
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs
  14. 3
      framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs
  15. 4
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs
  16. 12
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs
  17. 8
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs
  18. 24
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs
  19. 28
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs
  20. 1
      modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs
  21. 8
      modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs
  22. 8
      modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs
  23. 44
      modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs
  24. 11
      modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs
  25. 7
      modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs
  26. 7
      modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs
  27. 5
      modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs
  28. 17
      modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs

14
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs

@ -23,13 +23,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
Cache = cache; Cache = cache;
} }
public async Task<TenantConfiguration?> FindAsync(string name) public async Task<TenantConfiguration?> FindAsync(string normalizedName)
{ {
var cacheKey = CreateCacheKey(name); var cacheKey = CreateCacheKey(normalizedName);
var tenantConfiguration = await Cache.GetOrAddAsync( var tenantConfiguration = await Cache.GetOrAddAsync(
cacheKey, cacheKey,
async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))!, async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName))!,
() => new DistributedCacheEntryOptions () => new DistributedCacheEntryOptions
{ {
AbsoluteExpirationRelativeToNow = AbsoluteExpirationRelativeToNow =
@ -57,13 +57,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
return tenantConfiguration; return tenantConfiguration;
} }
public TenantConfiguration? Find(string name) public TenantConfiguration? Find(string normalizedName)
{ {
var cacheKey = CreateCacheKey(name); var cacheKey = CreateCacheKey(normalizedName);
var tenantConfiguration = Cache.GetOrAdd( var tenantConfiguration = Cache.GetOrAdd(
cacheKey, cacheKey,
() => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name)))!, () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName)))!,
() => new DistributedCacheEntryOptions () => new DistributedCacheEntryOptions
{ {
AbsoluteExpirationRelativeToNow = AbsoluteExpirationRelativeToNow =
@ -110,4 +110,4 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
{ {
return $"RemoteTenantStore_Id_{tenantId:N}"; return $"RemoteTenantStore_Id_{tenantId:N}";
} }
} }

12
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs

@ -29,9 +29,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
Options = options.Value; Options = options.Value;
} }
public async Task<TenantConfiguration?> FindAsync(string name) public async Task<TenantConfiguration?> FindAsync(string normalizedName)
{ {
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name); var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName);
var httpContext = HttpContextAccessor?.HttpContext; var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext) if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
@ -42,7 +42,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
var tenantConfiguration = await Cache.GetAsync(cacheKey); var tenantConfiguration = await Cache.GetAsync(cacheKey);
if (tenantConfiguration == null) if (tenantConfiguration == null)
{ {
await TenantAppService.FindTenantByNameAsync(name); await TenantAppService.FindTenantByNameAsync(normalizedName);
tenantConfiguration = await Cache.GetAsync(cacheKey); tenantConfiguration = await Cache.GetAsync(cacheKey);
} }
@ -79,9 +79,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
return tenantConfiguration?.Value; return tenantConfiguration?.Value;
} }
public TenantConfiguration? Find(string name) public TenantConfiguration? Find(string normalizedName)
{ {
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name); var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName);
var httpContext = HttpContextAccessor?.HttpContext; var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext) if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
@ -92,7 +92,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
var tenantConfiguration = Cache.Get(cacheKey); var tenantConfiguration = Cache.Get(cacheKey);
if (tenantConfiguration == null) if (tenantConfiguration == null)
{ {
AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(name)); AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(normalizedName));
tenantConfiguration = Cache.Get(cacheKey); tenantConfiguration = Cache.Get(cacheKey);
} }

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs

@ -11,5 +11,7 @@ public class FindTenantResultDto
public string? Name { get; set; } public string? Name { get; set; }
public string? NormalizedName { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
} }

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs

@ -9,15 +9,17 @@ namespace Pages.Abp.MultiTenancy;
public class AbpTenantAppService : ApplicationService, IAbpTenantAppService public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
{ {
protected ITenantStore TenantStore { get; } protected ITenantStore TenantStore { get; }
protected ITenantNormalizer TenantNormalizer { get; }
public AbpTenantAppService(ITenantStore tenantStore) public AbpTenantAppService(ITenantStore tenantStore, ITenantNormalizer tenantNormalizer)
{ {
TenantStore = tenantStore; TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
} }
public virtual async Task<FindTenantResultDto> FindTenantByNameAsync(string name) public virtual async Task<FindTenantResultDto> FindTenantByNameAsync(string name)
{ {
var tenant = await TenantStore.FindAsync(name); var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(name)!);
if (tenant == null) if (tenant == null)
{ {
@ -29,6 +31,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
Success = true, Success = true,
TenantId = tenant.Id, TenantId = tenant.Id,
Name = tenant.Name, Name = tenant.Name,
NormalizedName = tenant.NormalizedName,
IsActive = tenant.IsActive IsActive = tenant.IsActive
}; };
} }
@ -47,6 +50,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
Success = true, Success = true,
TenantId = tenant.Id, TenantId = tenant.Id,
Name = tenant.Name, Name = tenant.Name,
NormalizedName = tenant.NormalizedName,
IsActive = tenant.IsActive IsActive = tenant.IsActive
}; };
} }

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs

@ -18,13 +18,16 @@ public class TenantSwitchModalModel : AbpPageModel
public TenantInfoModel Input { get; set; } = default!; public TenantInfoModel Input { get; set; } = default!;
protected ITenantStore TenantStore { get; } protected ITenantStore TenantStore { get; }
protected ITenantNormalizer TenantNormalizer { get; }
protected AbpAspNetCoreMultiTenancyOptions Options { get; } protected AbpAspNetCoreMultiTenancyOptions Options { get; }
public TenantSwitchModalModel( public TenantSwitchModalModel(
ITenantStore tenantStore, ITenantStore tenantStore,
ITenantNormalizer tenantNormalizer,
IOptions<AbpAspNetCoreMultiTenancyOptions> options) IOptions<AbpAspNetCoreMultiTenancyOptions> options)
{ {
TenantStore = tenantStore; TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
Options = options.Value; Options = options.Value;
LocalizationResourceType = typeof(AbpUiMultiTenancyResource); LocalizationResourceType = typeof(AbpUiMultiTenancyResource);
} }
@ -45,7 +48,7 @@ public class TenantSwitchModalModel : AbpPageModel
Guid? tenantId = null; Guid? tenantId = null;
if (!Input.Name.IsNullOrEmpty()) if (!Input.Name.IsNullOrEmpty())
{ {
var tenant = await TenantStore.FindAsync(Input.Name!); var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!);
if (tenant == null) if (tenant == null)
{ {
throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]); throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]);

6
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantNormalizer.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.MultiTenancy;
public interface ITenantNormalizer
{
string? NormalizeName(string? name);
}

4
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantStore.cs

@ -5,12 +5,12 @@ namespace Volo.Abp.MultiTenancy;
public interface ITenantStore public interface ITenantStore
{ {
Task<TenantConfiguration?> FindAsync(string name); Task<TenantConfiguration?> FindAsync(string normalizedName);
Task<TenantConfiguration?> FindAsync(Guid id); Task<TenantConfiguration?> FindAsync(Guid id);
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]
TenantConfiguration? Find(string name); TenantConfiguration? Find(string normalizedName);
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]
TenantConfiguration? Find(Guid id); TenantConfiguration? Find(Guid id);

10
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs

@ -11,6 +11,8 @@ public class TenantConfiguration
public string Name { get; set; } = default!; public string Name { get; set; } = default!;
public string NormalizedName { get; set; } = default!;
public ConnectionStrings? ConnectionStrings { get; set; } public ConnectionStrings? ConnectionStrings { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
@ -30,4 +32,12 @@ public class TenantConfiguration
ConnectionStrings = new ConnectionStrings(); ConnectionStrings = new ConnectionStrings();
} }
public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName)
: this(id, name)
{
Check.NotNull(normalizedName, nameof(normalizedName));
NormalizedName = normalizedName;
}
} }

11
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/UpperInvariantTenantNormalizer.cs

@ -0,0 +1,11 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.MultiTenancy;
public class UpperInvariantTenantNormalizer : ITenantNormalizer, ITransientDependency
{
public virtual string? NormalizeName(string? name)
{
return name?.Normalize().ToUpperInvariant();
}
}

8
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/DefaultTenantStore.cs

@ -16,9 +16,9 @@ public class DefaultTenantStore : ITenantStore, ITransientDependency
_options = options.CurrentValue; _options = options.CurrentValue;
} }
public Task<TenantConfiguration?> FindAsync(string name) public Task<TenantConfiguration?> FindAsync(string normalizedName)
{ {
return Task.FromResult(Find(name)); return Task.FromResult(Find(normalizedName));
} }
public Task<TenantConfiguration?> FindAsync(Guid id) public Task<TenantConfiguration?> FindAsync(Guid id)
@ -26,9 +26,9 @@ public class DefaultTenantStore : ITenantStore, ITransientDependency
return Task.FromResult(Find(id)); return Task.FromResult(Find(id));
} }
public TenantConfiguration? Find(string name) public TenantConfiguration? Find(string normalizedName)
{ {
return _options.Tenants?.FirstOrDefault(t => t.Name == name); return _options.Tenants?.FirstOrDefault(t => t.NormalizedName == normalizedName);
} }
public TenantConfiguration? Find(Guid id) public TenantConfiguration? Find(Guid id)

7
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfigurationProvider.cs

@ -10,6 +10,7 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
{ {
protected virtual ITenantResolver TenantResolver { get; } protected virtual ITenantResolver TenantResolver { get; }
protected virtual ITenantStore TenantStore { get; } protected virtual ITenantStore TenantStore { get; }
protected virtual ITenantNormalizer TenantNormalizer { get; }
protected virtual ITenantResolveResultAccessor TenantResolveResultAccessor { get; } protected virtual ITenantResolveResultAccessor TenantResolveResultAccessor { get; }
protected virtual IStringLocalizer<AbpMultiTenancyResource> StringLocalizer { get; } protected virtual IStringLocalizer<AbpMultiTenancyResource> StringLocalizer { get; }
@ -17,10 +18,12 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
ITenantResolver tenantResolver, ITenantResolver tenantResolver,
ITenantStore tenantStore, ITenantStore tenantStore,
ITenantResolveResultAccessor tenantResolveResultAccessor, ITenantResolveResultAccessor tenantResolveResultAccessor,
IStringLocalizer<AbpMultiTenancyResource> stringLocalizer) IStringLocalizer<AbpMultiTenancyResource> stringLocalizer,
ITenantNormalizer tenantNormalizer)
{ {
TenantResolver = tenantResolver; TenantResolver = tenantResolver;
TenantStore = tenantStore; TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
TenantResolveResultAccessor = tenantResolveResultAccessor; TenantResolveResultAccessor = tenantResolveResultAccessor;
StringLocalizer = stringLocalizer; StringLocalizer = stringLocalizer;
} }
@ -69,7 +72,7 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
} }
else else
{ {
return await TenantStore.FindAsync(tenantIdOrName); return await TenantStore.FindAsync(TenantNormalizer.NormalizeName(tenantIdOrName)!);
} }
} }
} }

3
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs

@ -16,6 +16,7 @@ public class AspNetCoreMultiTenancy_WithDomainResolver_Tests : AspNetCoreMultiTe
{ {
private readonly Guid _testTenantId = Guid.NewGuid(); private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme"; private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _options; private readonly AbpAspNetCoreMultiTenancyOptions _options;
@ -30,7 +31,7 @@ public class AspNetCoreMultiTenancy_WithDomainResolver_Tests : AspNetCoreMultiTe
{ {
options.Tenants = new[] options.Tenants = new[]
{ {
new TenantConfiguration(_testTenantId, _testTenantName) new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
}; };
}); });

3
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs

@ -17,6 +17,7 @@ public class AspNetCoreMultiTenancy_Without_DomainResolver_Tests : AspNetCoreMul
{ {
private readonly Guid _testTenantId = Guid.NewGuid(); private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme"; private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _options; private readonly AbpAspNetCoreMultiTenancyOptions _options;
@ -31,7 +32,7 @@ public class AspNetCoreMultiTenancy_Without_DomainResolver_Tests : AspNetCoreMul
{ {
options.Tenants = new[] options.Tenants = new[]
{ {
new TenantConfiguration(_testTenantId, _testTenantName) new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
}; };
}); });

3
framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs

@ -20,6 +20,7 @@ public class Serilog_Enrichers_Tests : AbpSerilogTestBase
private readonly Guid _testTenantId = Guid.NewGuid(); private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme"; private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _tenancyOptions; private readonly AbpAspNetCoreMultiTenancyOptions _tenancyOptions;
private readonly AbpAspNetCoreSerilogOptions _serilogOptions; private readonly AbpAspNetCoreSerilogOptions _serilogOptions;
@ -39,7 +40,7 @@ public class Serilog_Enrichers_Tests : AbpSerilogTestBase
{ {
options.Tenants = new[] options.Tenants = new[]
{ {
new TenantConfiguration(_testTenantId, _testTenantName) new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
}; };
}); });
base.ConfigureServices(services); base.ConfigureServices(services);

4
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs

@ -9,13 +9,13 @@ namespace Volo.Abp.TenantManagement;
public interface ITenantRepository : IBasicRepository<Tenant, Guid> public interface ITenantRepository : IBasicRepository<Tenant, Guid>
{ {
Task<Tenant> FindByNameAsync( Task<Tenant> FindByNameAsync(
string name, string normalizedName,
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
[Obsolete("Use FindByNameAsync method.")] [Obsolete("Use FindByNameAsync method.")]
Tenant FindByName( Tenant FindByName(
string name, string normalizedName,
bool includeDetails = true bool includeDetails = true
); );

12
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs

@ -10,7 +10,9 @@ namespace Volo.Abp.TenantManagement;
public class Tenant : FullAuditedAggregateRoot<Guid>, IHasEntityVersion public class Tenant : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
{ {
public virtual string Name { get; protected set; } public virtual string Name { get; protected set; }
public virtual string NormalizedName { get; protected set; }
public virtual int EntityVersion { get; protected set; } public virtual int EntityVersion { get; protected set; }
public virtual List<TenantConnectionString> ConnectionStrings { get; protected set; } public virtual List<TenantConnectionString> ConnectionStrings { get; protected set; }
@ -20,10 +22,11 @@ public class Tenant : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
} }
protected internal Tenant(Guid id, [NotNull] string name) protected internal Tenant(Guid id, [NotNull] string name, [CanBeNull] string normalizedTenantName)
: base(id) : base(id)
{ {
SetName(name); SetName(name);
SetNormalizedTenantName(normalizedTenantName);
ConnectionStrings = new List<TenantConnectionString>(); ConnectionStrings = new List<TenantConnectionString>();
} }
@ -78,4 +81,9 @@ public class Tenant : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
{ {
Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength); Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength);
} }
protected internal virtual void SetNormalizedTenantName([CanBeNull] string normalizedTenantName)
{
NormalizedName = normalizedTenantName;
}
} }

8
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs

@ -22,21 +22,21 @@ public class TenantConfigurationCacheItemInvalidator :
public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData) public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData)
{ {
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name); await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName);
} }
public virtual async Task HandleEventAsync(EntityDeletedEventData<Tenant> eventData) public virtual async Task HandleEventAsync(EntityDeletedEventData<Tenant> eventData)
{ {
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name); await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName);
} }
protected virtual async Task ClearCacheAsync(Guid? id, string name) protected virtual async Task ClearCacheAsync(Guid? id, string normalizedName)
{ {
await Cache.RemoveManyAsync( await Cache.RemoveManyAsync(
new[] new[]
{ {
TenantConfigurationCacheItem.CalculateCacheKey(id, null), TenantConfigurationCacheItem.CalculateCacheKey(id, null),
TenantConfigurationCacheItem.CalculateCacheKey(null, name), TenantConfigurationCacheItem.CalculateCacheKey(null, normalizedName),
}); });
} }
} }

24
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs

@ -11,19 +11,22 @@ public class TenantManager : DomainService, ITenantManager
protected ITenantRepository TenantRepository { get; } protected ITenantRepository TenantRepository { get; }
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; } protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }
public TenantManager(ITenantRepository tenantRepository, protected ITenantNormalizer TenantNormalizer { get; }
IDistributedCache<TenantConfigurationCacheItem> cache)
public TenantManager(ITenantRepository tenantRepository, IDistributedCache<TenantConfigurationCacheItem> cache, ITenantNormalizer tenantNormalizer)
{ {
TenantRepository = tenantRepository; TenantRepository = tenantRepository;
Cache = cache; Cache = cache;
TenantNormalizer = tenantNormalizer;
} }
public virtual async Task<Tenant> CreateAsync(string name) public virtual async Task<Tenant> CreateAsync(string name)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
await ValidateNameAsync(name); var normalizedTenantName = TenantNormalizer.NormalizeName(name);
return new Tenant(GuidGenerator.Create(), name); await ValidateNameAsync(normalizedTenantName);
return new Tenant(GuidGenerator.Create(), name, normalizedTenantName);
} }
public virtual async Task ChangeNameAsync(Tenant tenant, string name) public virtual async Task ChangeNameAsync(Tenant tenant, string name)
@ -31,17 +34,20 @@ public class TenantManager : DomainService, ITenantManager
Check.NotNull(tenant, nameof(tenant)); Check.NotNull(tenant, nameof(tenant));
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
await ValidateNameAsync(name, tenant.Id); var normalizedTenantName = TenantNormalizer.NormalizeName(name);
await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.Name));
await ValidateNameAsync(normalizedTenantName, tenant.Id);
await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.NormalizedName));
tenant.SetName(name); tenant.SetName(name);
tenant.SetNormalizedTenantName(normalizedTenantName);
} }
protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null) protected virtual async Task ValidateNameAsync(string normalizeName, Guid? expectedId = null)
{ {
var tenant = await TenantRepository.FindByNameAsync(name); var tenant = await TenantRepository.FindByNameAsync(normalizeName);
if (tenant != null && tenant.Id != expectedId) if (tenant != null && tenant.Id != expectedId)
{ {
throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", name); throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", normalizeName);
} }
} }
} }

28
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs

@ -27,9 +27,9 @@ public class TenantStore : ITenantStore, ITransientDependency
Cache = cache; Cache = cache;
} }
public virtual async Task<TenantConfiguration> FindAsync(string name) public virtual async Task<TenantConfiguration> FindAsync(string normalizedName)
{ {
return (await GetCacheItemAsync(null, name)).Value; return (await GetCacheItemAsync(null, normalizedName)).Value;
} }
public virtual async Task<TenantConfiguration> FindAsync(Guid id) public virtual async Task<TenantConfiguration> FindAsync(Guid id)
@ -38,9 +38,9 @@ public class TenantStore : ITenantStore, ITransientDependency
} }
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]
public virtual TenantConfiguration Find(string name) public virtual TenantConfiguration Find(string normalizedName)
{ {
return (GetCacheItem(null, name)).Value; return (GetCacheItem(null, normalizedName)).Value;
} }
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]
@ -49,9 +49,9 @@ public class TenantStore : ITenantStore, ITransientDependency
return (GetCacheItem(id, null)).Value; return (GetCacheItem(id, null)).Value;
} }
protected virtual async Task<TenantConfigurationCacheItem> GetCacheItemAsync(Guid? id, string name) protected virtual async Task<TenantConfigurationCacheItem> GetCacheItemAsync(Guid? id, string normalizedName)
{ {
var cacheKey = CalculateCacheKey(id, name); var cacheKey = CalculateCacheKey(id, normalizedName);
var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true);
if (cacheItem != null) if (cacheItem != null)
@ -68,11 +68,11 @@ public class TenantStore : ITenantStore, ITransientDependency
} }
} }
if (!name.IsNullOrWhiteSpace()) if (!normalizedName.IsNullOrWhiteSpace())
{ {
using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{ {
var tenant = await TenantRepository.FindByNameAsync(name); var tenant = await TenantRepository.FindByNameAsync(normalizedName);
return await SetCacheAsync(cacheKey, tenant); return await SetCacheAsync(cacheKey, tenant);
} }
} }
@ -89,9 +89,9 @@ public class TenantStore : ITenantStore, ITransientDependency
} }
[Obsolete("Use GetCacheItemAsync method.")] [Obsolete("Use GetCacheItemAsync method.")]
protected virtual TenantConfigurationCacheItem GetCacheItem(Guid? id, string name) protected virtual TenantConfigurationCacheItem GetCacheItem(Guid? id, string normalizedName)
{ {
var cacheKey = CalculateCacheKey(id, name); var cacheKey = CalculateCacheKey(id, normalizedName);
var cacheItem = Cache.Get(cacheKey, considerUow: true); var cacheItem = Cache.Get(cacheKey, considerUow: true);
if (cacheItem != null) if (cacheItem != null)
@ -108,11 +108,11 @@ public class TenantStore : ITenantStore, ITransientDependency
} }
} }
if (!name.IsNullOrWhiteSpace()) if (!normalizedName.IsNullOrWhiteSpace())
{ {
using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{ {
var tenant = TenantRepository.FindByName(name); var tenant = TenantRepository.FindByName(normalizedName);
return SetCache(cacheKey, tenant); return SetCache(cacheKey, tenant);
} }
} }
@ -129,8 +129,8 @@ public class TenantStore : ITenantStore, ITransientDependency
return cacheItem; return cacheItem;
} }
protected virtual string CalculateCacheKey(Guid? id, string name) protected virtual string CalculateCacheKey(Guid? id, string normalizedName)
{ {
return TenantConfigurationCacheItem.CalculateCacheKey(id, name); return TenantConfigurationCacheItem.CalculateCacheKey(id, normalizedName);
} }
} }

1
modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs

@ -23,6 +23,7 @@ public static class AbpTenantManagementDbContextModelCreatingExtensions
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(t => t.Name).IsRequired().HasMaxLength(TenantConsts.MaxNameLength); b.Property(t => t.Name).IsRequired().HasMaxLength(TenantConsts.MaxNameLength);
b.Property(t => t.NormalizedName).IsRequired().HasMaxLength(TenantConsts.MaxNameLength);
b.HasMany(u => u.ConnectionStrings).WithOne().HasForeignKey(uc => uc.TenantId).IsRequired(); b.HasMany(u => u.ConnectionStrings).WithOne().HasForeignKey(uc => uc.TenantId).IsRequired();

8
modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs

@ -19,23 +19,23 @@ public class EfCoreTenantRepository : EfCoreRepository<ITenantManagementDbContex
} }
public virtual async Task<Tenant> FindByNameAsync( public virtual async Task<Tenant> FindByNameAsync(
string name, string normalizedName,
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.IncludeDetails(includeDetails) .IncludeDetails(includeDetails)
.OrderBy(t => t.Id) .OrderBy(t => t.Id)
.FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); .FirstOrDefaultAsync(t => t.NormalizedName == normalizedName, GetCancellationToken(cancellationToken));
} }
[Obsolete("Use FindByNameAsync method.")] [Obsolete("Use FindByNameAsync method.")]
public virtual Tenant FindByName(string name, bool includeDetails = true) public virtual Tenant FindByName(string normalizedName, bool includeDetails = true)
{ {
return DbSet return DbSet
.IncludeDetails(includeDetails) .IncludeDetails(includeDetails)
.OrderBy(t => t.Id) .OrderBy(t => t.Id)
.FirstOrDefault(t => t.Name == name); .FirstOrDefault(t => t.NormalizedName == normalizedName);
} }
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]

8
modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs

@ -20,19 +20,19 @@ public class MongoTenantRepository : MongoDbRepository<ITenantManagementMongoDbC
} }
public virtual async Task<Tenant> FindByNameAsync( public virtual async Task<Tenant> FindByNameAsync(
string name, string normalizedName,
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetMongoQueryableAsync(cancellationToken))
.FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); .FirstOrDefaultAsync(t => t.NormalizedName == normalizedName, GetCancellationToken(cancellationToken));
} }
[Obsolete("Use FindByNameAsync method.")] [Obsolete("Use FindByNameAsync method.")]
public virtual Tenant FindByName(string name, bool includeDetails = true) public virtual Tenant FindByName(string normalizedName, bool includeDetails = true)
{ {
return GetMongoQueryable() return GetMongoQueryable()
.FirstOrDefault(t => t.Name == name); .FirstOrDefault(t => t.NormalizedName == normalizedName);
} }
[Obsolete("Use FindAsync method.")] [Obsolete("Use FindAsync method.")]

44
modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs

@ -12,6 +12,7 @@ public class TenantConfigurationCacheItemInvalidator_Tests : AbpTenantManagement
private readonly ITenantStore _tenantStore; private readonly ITenantStore _tenantStore;
private readonly ITenantRepository _tenantRepository; private readonly ITenantRepository _tenantRepository;
private readonly ITenantManager _tenantManager; private readonly ITenantManager _tenantManager;
private readonly ITenantNormalizer _tenantNormalizer;
public TenantConfigurationCacheItemInvalidator_Tests() public TenantConfigurationCacheItemInvalidator_Tests()
{ {
@ -19,86 +20,87 @@ public class TenantConfigurationCacheItemInvalidator_Tests : AbpTenantManagement
_tenantStore = GetRequiredService<ITenantStore>(); _tenantStore = GetRequiredService<ITenantStore>();
_tenantRepository = GetRequiredService<ITenantRepository>(); _tenantRepository = GetRequiredService<ITenantRepository>();
_tenantManager = GetRequiredService<ITenantManager>(); _tenantManager = GetRequiredService<ITenantManager>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
public async Task Get_Tenant_Should_Cached() public async Task Get_Tenant_Should_Cached()
{ {
var acme = await _tenantRepository.FindByNameAsync("acme"); var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull();
await _tenantStore.FindAsync(acme.Id); await _tenantStore.FindAsync(acme.Id);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull();
await _tenantStore.FindAsync(acme.Name); await _tenantStore.FindAsync(acme.NormalizedName);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull();
var volosoft = _tenantRepository.FindByName("volosoft"); var volosoft = _tenantRepository.FindByName(_tenantNormalizer.NormalizeName("volosoft"));
volosoft.ShouldNotBeNull(); volosoft.ShouldNotBeNull();
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull();
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldBeNull();
_tenantStore.Find(volosoft.Id); _tenantStore.Find(volosoft.Id);
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull();
_tenantStore.Find(volosoft.Name); _tenantStore.Find(volosoft.NormalizedName);
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldNotBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldNotBeNull();
} }
[Fact] [Fact]
public async Task Cache_Should_Invalidator_When_Tenant_Changed() public async Task Cache_Should_Invalidator_When_Tenant_Changed()
{ {
var acme = await _tenantRepository.FindByNameAsync("acme"); var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
// FindAsync will cache tenant. // FindAsync will cache tenant.
await _tenantStore.FindAsync(acme.Id); await _tenantStore.FindAsync(acme.Id);
await _tenantStore.FindAsync(acme.Name); await _tenantStore.FindAsync(acme.NormalizedName);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull();
await _tenantRepository.DeleteAsync(acme); await _tenantRepository.DeleteAsync(acme);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull();
var volosoft = await _tenantRepository.FindByNameAsync("volosoft"); var volosoft = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("volosoft"));
volosoft.ShouldNotBeNull(); volosoft.ShouldNotBeNull();
// Find will cache tenant. // Find will cache tenant.
_tenantStore.Find(volosoft.Id); _tenantStore.Find(volosoft.Id);
_tenantStore.Find(volosoft.Name); _tenantStore.Find(volosoft.NormalizedName);
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull();
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldNotBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldNotBeNull();
await _tenantRepository.DeleteAsync(volosoft); await _tenantRepository.DeleteAsync(volosoft);
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull();
(_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldBeNull();
var abp = await _tenantRepository.FindByNameAsync("abp"); var abp = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("abp"));
abp.ShouldNotBeNull(); abp.ShouldNotBeNull();
// Find will cache tenant. // Find will cache tenant.
await _tenantStore.FindAsync(abp.Id); await _tenantStore.FindAsync(abp.Id);
await _tenantStore.FindAsync(abp.Name); await _tenantStore.FindAsync(abp.NormalizedName);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldNotBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, abp.Name))).ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, abp.NormalizedName))).ShouldNotBeNull();
await _tenantManager.ChangeNameAsync(abp, "abp2"); await _tenantManager.ChangeNameAsync(abp, "abp2");
await _tenantRepository.UpdateAsync(abp); await _tenantRepository.UpdateAsync(abp);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, "abp"))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, _tenantNormalizer.NormalizeName("abp")))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, "abp2"))).ShouldBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, _tenantNormalizer.NormalizeName("abp2")))).ShouldBeNull();
} }
} }

11
modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs

@ -1,5 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.MultiTenancy;
using Xunit; using Xunit;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
@ -8,19 +9,21 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase
{ {
private readonly ITenantManager _tenantManager; private readonly ITenantManager _tenantManager;
private readonly ITenantRepository _tenantRepository; private readonly ITenantRepository _tenantRepository;
private readonly ITenantNormalizer _tenantNormalizer;
public TenantManager_Tests() public TenantManager_Tests()
{ {
_tenantManager = GetRequiredService<ITenantManager>(); _tenantManager = GetRequiredService<ITenantManager>();
_tenantRepository = GetRequiredService<ITenantRepository>(); _tenantRepository = GetRequiredService<ITenantRepository>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
public async Task CreateAsync() public async Task CreateAsync()
{ {
var tenant = await _tenantManager.CreateAsync("Test"); var tenant = await _tenantManager.CreateAsync("Test");
tenant.Name.ShouldBe("Test"); tenant.Name.ShouldBe("Test");
tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("Test"));
} }
[Fact] [Fact]
@ -32,18 +35,20 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase
[Fact] [Fact]
public async Task ChangeNameAsync() public async Task ChangeNameAsync()
{ {
var tenant = await _tenantRepository.FindByNameAsync("volosoft"); var tenant = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("volosoft"));
tenant.ShouldNotBeNull(); tenant.ShouldNotBeNull();
tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("volosoft"));
await _tenantManager.ChangeNameAsync(tenant, "newVolosoft"); await _tenantManager.ChangeNameAsync(tenant, "newVolosoft");
tenant.Name.ShouldBe("newVolosoft"); tenant.Name.ShouldBe("newVolosoft");
tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("newVolosoft"));
} }
[Fact] [Fact]
public async Task ChangeName_Tenant_Name_Can_Not_Duplicate() public async Task ChangeName_Tenant_Name_Can_Not_Duplicate()
{ {
var tenant = await _tenantRepository.FindByNameAsync("acme"); var tenant = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
tenant.ShouldNotBeNull(); tenant.ShouldNotBeNull();
await Assert.ThrowsAsync<BusinessException>(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); await Assert.ThrowsAsync<BusinessException>(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft"));

7
modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs

@ -9,25 +9,28 @@ public class TenantStore_Tests : AbpTenantManagementDomainTestBase
{ {
private readonly ITenantStore _tenantStore; private readonly ITenantStore _tenantStore;
private readonly ITenantRepository _tenantRepository; private readonly ITenantRepository _tenantRepository;
private readonly ITenantNormalizer _tenantNormalizer;
public TenantStore_Tests() public TenantStore_Tests()
{ {
_tenantStore = GetRequiredService<ITenantStore>(); _tenantStore = GetRequiredService<ITenantStore>();
_tenantRepository = GetRequiredService<ITenantRepository>(); _tenantRepository = GetRequiredService<ITenantRepository>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
public async Task FindAsyncByName() public async Task FindAsyncByName()
{ {
var acme = await _tenantStore.FindAsync("acme"); var acme = await _tenantStore.FindAsync(_tenantNormalizer.NormalizeName("acme")!);
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
acme.Name.ShouldBe("acme"); acme.Name.ShouldBe("acme");
acme.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("acme")!);
} }
[Fact] [Fact]
public async Task FindAsyncById() public async Task FindAsyncById()
{ {
var acme = await _tenantRepository.FindByNameAsync("acme"); var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
(await _tenantStore.FindAsync(acme.Id)).ShouldNotBeNull(); (await _tenantStore.FindAsync(acme.Id)).ShouldNotBeNull();

7
modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs

@ -1,5 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.MultiTenancy;
using Xunit; using Xunit;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
@ -7,16 +8,18 @@ namespace Volo.Abp.TenantManagement;
public class Tenant_Tests : AbpTenantManagementDomainTestBase public class Tenant_Tests : AbpTenantManagementDomainTestBase
{ {
private readonly ITenantRepository _tenantRepository; private readonly ITenantRepository _tenantRepository;
private readonly ITenantNormalizer _tenantNormalizer;
public Tenant_Tests() public Tenant_Tests()
{ {
_tenantRepository = GetRequiredService<ITenantRepository>(); _tenantRepository = GetRequiredService<ITenantRepository>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
public async Task FindDefaultConnectionString() public async Task FindDefaultConnectionString()
{ {
var acme = await _tenantRepository.FindByNameAsync("acme"); var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
acme.FindDefaultConnectionString().ShouldBe("DefaultConnString-Value"); acme.FindDefaultConnectionString().ShouldBe("DefaultConnString-Value");
@ -25,7 +28,7 @@ public class Tenant_Tests : AbpTenantManagementDomainTestBase
[Fact] [Fact]
public async Task FindConnectionString() public async Task FindConnectionString()
{ {
var acme = await _tenantRepository.FindByNameAsync("acme"); var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
acme.ShouldNotBeNull(); acme.ShouldNotBeNull();
acme.FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName).ShouldBe("DefaultConnString-Value"); acme.FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName).ShouldBe("DefaultConnString-Value");

5
modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs

@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow; using Volo.Abp.Uow;
using Xunit; using Xunit;
@ -11,10 +12,12 @@ public abstract class LazyLoad_Tests<TStartupModule> : TenantManagementTestBase<
where TStartupModule : IAbpModule where TStartupModule : IAbpModule
{ {
public ITenantRepository TenantRepository { get; } public ITenantRepository TenantRepository { get; }
public ITenantNormalizer TenantNormalizer { get; }
protected LazyLoad_Tests() protected LazyLoad_Tests()
{ {
TenantRepository = GetRequiredService<ITenantRepository>(); TenantRepository = GetRequiredService<ITenantRepository>();
TenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
@ -22,7 +25,7 @@ public abstract class LazyLoad_Tests<TStartupModule> : TenantManagementTestBase<
{ {
using (var uow = GetRequiredService<IUnitOfWorkManager>().Begin()) using (var uow = GetRequiredService<IUnitOfWorkManager>().Begin())
{ {
var role = await TenantRepository.FindByNameAsync("acme", includeDetails: false); var role = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"), includeDetails: false);
role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.ShouldNotBeNull();
role.ConnectionStrings.Any().ShouldBeTrue(); role.ConnectionStrings.Any().ShouldBeTrue();

17
modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Xunit; using Xunit;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
@ -11,22 +12,24 @@ public abstract class TenantRepository_Tests<TStartupModule> : TenantManagementT
where TStartupModule : IAbpModule where TStartupModule : IAbpModule
{ {
public ITenantRepository TenantRepository { get; } public ITenantRepository TenantRepository { get; }
public ITenantNormalizer TenantNormalizer { get; }
protected TenantRepository_Tests() protected TenantRepository_Tests()
{ {
TenantRepository = GetRequiredService<ITenantRepository>(); TenantRepository = GetRequiredService<ITenantRepository>();
TenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
public async Task FindByNameAsync() public async Task FindByNameAsync()
{ {
var tenant = await TenantRepository.FindByNameAsync("acme"); var tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"));
tenant.ShouldNotBeNull(); tenant.ShouldNotBeNull();
tenant = await TenantRepository.FindByNameAsync("undefined-tenant"); tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("undefined-tenant"));
tenant.ShouldBeNull(); tenant.ShouldBeNull();
tenant = await TenantRepository.FindByNameAsync("acme", includeDetails: true); tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"), includeDetails: true);
tenant.ShouldNotBeNull(); tenant.ShouldNotBeNull();
tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2); tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2);
} }
@ -34,7 +37,7 @@ public abstract class TenantRepository_Tests<TStartupModule> : TenantManagementT
[Fact] [Fact]
public async Task FindAsync() public async Task FindAsync()
{ {
var tenantId = (await TenantRepository.FindByNameAsync("acme")).Id; var tenantId = (await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"))).Id;
var tenant = await TenantRepository.FindAsync(tenantId); var tenant = await TenantRepository.FindAsync(tenantId);
tenant.ShouldNotBeNull(); tenant.ShouldNotBeNull();
@ -51,14 +54,14 @@ public abstract class TenantRepository_Tests<TStartupModule> : TenantManagementT
public async Task GetListAsync() public async Task GetListAsync()
{ {
var tenants = await TenantRepository.GetListAsync(); var tenants = await TenantRepository.GetListAsync();
tenants.ShouldContain(t => t.Name == "acme"); tenants.ShouldContain(t => t.Name == "acme" && t.NormalizedName == TenantNormalizer.NormalizeName("acme"));
tenants.ShouldContain(t => t.Name == "volosoft"); tenants.ShouldContain(t => t.Name == "volosoft" && t.NormalizedName == TenantNormalizer.NormalizeName("volosoft"));
} }
[Fact] [Fact]
public async Task Should_Eager_Load_Tenant_Collections() public async Task Should_Eager_Load_Tenant_Collections()
{ {
var role = await TenantRepository.FindByNameAsync("acme"); var role = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"));
role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.ShouldNotBeNull();
role.ConnectionStrings.Any().ShouldBeTrue(); role.ConnectionStrings.Any().ShouldBeTrue();
} }

Loading…
Cancel
Save