mirror of https://github.com/abpframework/abp.git
43 changed files with 651 additions and 53 deletions
@ -1,13 +0,0 @@ |
|||||
namespace Volo.Abp.Application.Dtos |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// This interface is defined to standardize to set "Total Count of Items" to a DTO for long type.
|
|
||||
/// </summary>
|
|
||||
public interface IHasLongTotalCount |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Total count of Items.
|
|
||||
/// </summary>
|
|
||||
long TotalCount { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,6 +1,6 @@ |
|||||
using AutoMapper; |
using AutoMapper; |
||||
|
|
||||
namespace Volo.Abp.Identity.ObjectMappings |
namespace Volo.Abp.Identity |
||||
{ |
{ |
||||
public class AbpIdentityApplicationModuleAutoMapperProfile : Profile |
public class AbpIdentityApplicationModuleAutoMapperProfile : Profile |
||||
{ |
{ |
||||
@ -0,0 +1,21 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<AssemblyName>Volo.Abp.MultiTenancy.Application.Contracts</AssemblyName> |
||||
|
<PackageId>Volo.Abp.MultiTenancy.Application.Contracts</PackageId> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Volo.Abp.Ddd\Volo.Abp.Ddd.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.MultiTenancy.Domain.Shared\Volo.Abp.MultiTenancy.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpDddModule))] |
||||
|
[DependsOn(typeof(AbpMultiTenancyDomainSharedModule))] |
||||
|
public class AbpMultiTenancyApplicationContractsModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddAssemblyOf<AbpMultiTenancyApplicationContractsModule>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class GetTenantsInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public string Filter { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public interface ITenantAppService : IAsyncCrudAppService<TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto> |
||||
|
{ |
||||
|
//TODO: Manage connection strings
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantCreateDto : TenantCreateOrUpdateDtoBase |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public abstract class TenantCreateOrUpdateDtoBase |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantDto : EntityDto<Guid> |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantUpdateDto : TenantCreateOrUpdateDtoBase |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<AssemblyName>Volo.Abp.MultiTenancy.Application</AssemblyName> |
||||
|
<PackageId>Volo.Abp.MultiTenancy.Application</PackageId> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Volo.Abp.MultiTenancy.Application.Contracts\Volo.Abp.MultiTenancy.Application.Contracts.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.MultiTenancy.Domain\Volo.Abp.MultiTenancy.Domain.csproj" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.UI\Volo.Abp.UI.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpMultiTenancyDomainModule))] |
||||
|
[DependsOn(typeof(AbpMultiTenancyApplicationContractsModule))] |
||||
|
public class AbpMultiTenancyApplicationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddProfile<AbpMultiTenancyApplicationModuleAutoMapperProfile>(validate: true); |
||||
|
}); |
||||
|
|
||||
|
services.AddAssemblyOf<AbpMultiTenancyApplicationModule>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using AutoMapper; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class AbpMultiTenancyApplicationModuleAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public AbpMultiTenancyApplicationModuleAutoMapperProfile() |
||||
|
{ |
||||
|
CreateMap<Tenant, TenantDto>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class MultiTenancyAppServiceBase : ApplicationService |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantAppService : MultiTenancyAppServiceBase, ITenantAppService |
||||
|
{ |
||||
|
private readonly ITenantRepository _tenantRepository; |
||||
|
private readonly ITenantManager _tenantManager; |
||||
|
|
||||
|
public TenantAppService(ITenantRepository tenantRepository, ITenantManager tenantManager) |
||||
|
{ |
||||
|
_tenantRepository = tenantRepository; |
||||
|
_tenantManager = tenantManager; |
||||
|
} |
||||
|
|
||||
|
public async Task<TenantDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
return ObjectMapper.Map<Tenant, TenantDto>( |
||||
|
await _tenantRepository.GetAsync(id) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public async Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInput input) |
||||
|
{ |
||||
|
var count = await _tenantRepository.GetCountAsync(); |
||||
|
var list = await _tenantRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter); |
||||
|
|
||||
|
return new PagedResultDto<TenantDto>( |
||||
|
count, |
||||
|
ObjectMapper.Map<List<Tenant>, List<TenantDto>>(list) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public async Task<TenantDto> CreateAsync(TenantCreateDto input) |
||||
|
{ |
||||
|
var tenant = await _tenantManager.CreateAsync(input.Name); |
||||
|
await _tenantRepository.InsertAsync(tenant); |
||||
|
return ObjectMapper.Map<Tenant, TenantDto>(tenant); |
||||
|
} |
||||
|
|
||||
|
public async Task<TenantDto> UpdateAsync(Guid id, TenantUpdateDto input) |
||||
|
{ |
||||
|
var tenant = await _tenantRepository.GetAsync(id); |
||||
|
await _tenantManager.ChangeNameAsync(tenant, input.Name); |
||||
|
await _tenantRepository.UpdateAsync(tenant); |
||||
|
return ObjectMapper.Map<Tenant, TenantDto>(tenant); |
||||
|
} |
||||
|
|
||||
|
public async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var tenant = await _tenantRepository.FindAsync(id); |
||||
|
if (tenant == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
await _tenantRepository.DeleteAsync(tenant); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
||||
|
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Domain.Services; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public interface ITenantManager : IDomainService |
||||
|
{ |
||||
|
[NotNull] |
||||
|
Task<Tenant> CreateAsync([NotNull] string name); |
||||
|
|
||||
|
Task ChangeNameAsync([NotNull] Tenant tenant, [NotNull] string name); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Services; |
||||
|
using Volo.Abp.Ui; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantManager : DomainService, ITenantManager |
||||
|
{ |
||||
|
private readonly ITenantRepository _tenantRepository; |
||||
|
|
||||
|
public TenantManager(ITenantRepository tenantRepository) |
||||
|
{ |
||||
|
_tenantRepository = tenantRepository; |
||||
|
} |
||||
|
|
||||
|
public async Task<Tenant> CreateAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
await ValidateNameAsync(name); |
||||
|
return new Tenant(GuidGenerator.Create(), name); |
||||
|
} |
||||
|
|
||||
|
public async Task ChangeNameAsync(Tenant tenant, string name) |
||||
|
{ |
||||
|
Check.NotNull(tenant, nameof(tenant)); |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
await ValidateNameAsync(name, tenant.Id); |
||||
|
tenant.SetName(name); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null) |
||||
|
{ |
||||
|
var tenant = await _tenantRepository.FindByNameAsync(name); |
||||
|
if (tenant != null && tenant.Id != expectedId) |
||||
|
{ |
||||
|
throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..?
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
||||
|
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
||||
@ -1,30 +1,37 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
using Microsoft.EntityFrameworkCore; |
using Microsoft.EntityFrameworkCore; |
||||
|
|
||||
namespace Volo.Abp.MultiTenancy.EntityFrameworkCore |
namespace Volo.Abp.MultiTenancy.EntityFrameworkCore |
||||
{ |
{ |
||||
public static class MultiTenancyDbContextModelCreatingExtensions |
public static class MultiTenancyDbContextModelCreatingExtensions |
||||
{ |
{ |
||||
public static void ConfigureMultiTenancy(this IMultiTenancyDbContext dbContext, ModelBuilder builder) |
public static void ConfigureMultiTenancy(this IMultiTenancyDbContext dbContext, ModelBuilder builder, string tablePrefix = "", [CanBeNull] string schema = null) |
||||
{ |
{ |
||||
|
if (tablePrefix.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
tablePrefix = ""; |
||||
|
} |
||||
|
|
||||
builder.Entity<Tenant>(b => |
builder.Entity<Tenant>(b => |
||||
{ |
{ |
||||
b.ToTable("MtTenants"); //TODO: Make all table and schema names changeable
|
b.ToTable(tablePrefix + "Tenants", schema); |
||||
|
|
||||
b.Property(t => t.Name).IsRequired().HasMaxLength(TenantConsts.MaxNameLength); |
b.Property(t => t.Name).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(); |
||||
|
|
||||
b.HasIndex(u => u.Name); |
b.HasIndex(u => u.Name).IsUnique(); |
||||
}); |
}); |
||||
|
|
||||
builder.Entity<TenantConnectionString>(b => |
builder.Entity<TenantConnectionString>(b => |
||||
{ |
{ |
||||
b.ToTable("MtTenantConnectionStrings"); |
b.ToTable(tablePrefix + "TenantConnectionStrings", schema); |
||||
|
|
||||
|
b.HasKey(x => new {x.TenantId, x.Name}); |
||||
|
|
||||
b.Property(cs => cs.Name).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxNameLength); |
b.Property(cs => cs.Name).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxNameLength); |
||||
b.Property(cs => cs.Value).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxValueLength); |
b.Property(cs => cs.Value).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxValueLength); |
||||
|
|
||||
b.HasIndex(cs => cs.TenantId); |
|
||||
}); |
}); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,26 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp2.0</TargetFramework> |
||||
|
<AssemblyName>Volo.Abp.MultiTenancy.Application.Tests</AssemblyName> |
||||
|
<PackageId>Volo.Abp.MultiTenancy.Application.Tests</PackageId> |
||||
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.MultiTenancy.Application\Volo.Abp.MultiTenancy.Application.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.MultiTenancy.EntityFrameworkCore\Volo.Abp.MultiTenancy.EntityFrameworkCore.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> |
||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.MultiTenancy.EntityFrameworkCore; |
||||
|
using Volo.Abp.TestBase; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class AbpMultiTenancyApplicationTestBase : AbpIntegratedTest<AbpMultiTenancyApplicationTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
|
||||
|
protected virtual void UsingDbContext(Action<IMultiTenancyDbContext> action) |
||||
|
{ |
||||
|
using (var dbContext = GetRequiredService<IMultiTenancyDbContext>()) |
||||
|
{ |
||||
|
action.Invoke(dbContext); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual T UsingDbContext<T>(Func<IMultiTenancyDbContext, T> action) |
||||
|
{ |
||||
|
using (var dbContext = GetRequiredService<IMultiTenancyDbContext>()) |
||||
|
{ |
||||
|
return action.Invoke(dbContext); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,55 @@ |
|||||
|
using System; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.MultiTenancy.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpMultiTenancyApplicationModule), |
||||
|
typeof(AbpMultiTenancyEntityFrameworkCoreModule), |
||||
|
typeof(AbpAutofacModule))] |
||||
|
public class AbpMultiTenancyApplicationTestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddAssemblyOf<AbpMultiTenancyApplicationTestModule>(); |
||||
|
|
||||
|
services.AddEntityFrameworkInMemoryDatabase(); |
||||
|
|
||||
|
var databaseName = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
services.Configure<AbpDbContextOptions>(options => |
||||
|
{ |
||||
|
options.Configure(context => |
||||
|
{ |
||||
|
context.DbContextOptions.UseInMemoryDatabase(databaseName); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
services.Configure<UnitOfWorkDefaultOptions>(options => |
||||
|
{ |
||||
|
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
|
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
SeedTestData(context); |
||||
|
} |
||||
|
|
||||
|
private static void SeedTestData(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
using (var scope = context.ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
scope.ServiceProvider |
||||
|
.GetRequiredService<AbpMultiTenancyTestDataBuilder>() |
||||
|
.Build(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class AbpMultiTenancyTestDataBuilder : ITransientDependency |
||||
|
{ |
||||
|
private readonly ITenantRepository _tenantRepository; |
||||
|
private readonly ITenantManager _tenantManager; |
||||
|
|
||||
|
public AbpMultiTenancyTestDataBuilder( |
||||
|
ITenantRepository tenantRepository, |
||||
|
ITenantManager tenantManager) |
||||
|
{ |
||||
|
_tenantRepository = tenantRepository; |
||||
|
_tenantManager = tenantManager; |
||||
|
} |
||||
|
|
||||
|
public void Build() |
||||
|
{ |
||||
|
AsyncHelper.RunSync(AddTenantsAsync); |
||||
|
} |
||||
|
|
||||
|
private async Task AddTenantsAsync() |
||||
|
{ |
||||
|
var acme = await _tenantManager.CreateAsync("acme"); |
||||
|
await _tenantRepository.InsertAsync(acme); |
||||
|
|
||||
|
var volosoft = await _tenantManager.CreateAsync("volosoft"); |
||||
|
await _tenantRepository.InsertAsync(volosoft); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Ui; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class TenantAppService_Tests : AbpMultiTenancyApplicationTestBase |
||||
|
{ |
||||
|
private readonly ITenantAppService _tenantAppService; |
||||
|
|
||||
|
public TenantAppService_Tests() |
||||
|
{ |
||||
|
_tenantAppService = GetRequiredService<ITenantAppService>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetAsync() |
||||
|
{ |
||||
|
var tenantInDb = UsingDbContext(dbContext => dbContext.Tenants.First()); |
||||
|
var tenant = await _tenantAppService.GetAsync(tenantInDb.Id); |
||||
|
tenant.Name.ShouldBe(tenantInDb.Name); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetListAsync() |
||||
|
{ |
||||
|
var result = await _tenantAppService.GetListAsync(new GetTenantsInput()); |
||||
|
result.TotalCount.ShouldBeGreaterThan(0); |
||||
|
result.Items.ShouldContain(t => t.Name == "acme"); |
||||
|
result.Items.ShouldContain(t => t.Name == "volosoft"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetListAsync_Filtered() |
||||
|
{ |
||||
|
var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Filter = "volo" }); |
||||
|
result.TotalCount.ShouldBeGreaterThan(0); |
||||
|
result.Items.ShouldNotContain(t => t.Name == "acme"); |
||||
|
result.Items.ShouldContain(t => t.Name == "volosoft"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetListAsync_Sorted_Descending_By_Name() |
||||
|
{ |
||||
|
var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Sorting = "Name DESC" }); |
||||
|
result.TotalCount.ShouldBeGreaterThan(0); |
||||
|
var tenants = result.Items.ToList(); |
||||
|
|
||||
|
tenants.ShouldContain(t => t.Name == "acme"); |
||||
|
tenants.ShouldContain(t => t.Name == "volosoft"); |
||||
|
|
||||
|
tenants.FindIndex(t => t.Name == "acme").ShouldBeGreaterThan(tenants.FindIndex(t => t.Name == "volosoft")); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CreateAsync() |
||||
|
{ |
||||
|
var tenancyName = Guid.NewGuid().ToString("N").ToLowerInvariant(); |
||||
|
var tenant = await _tenantAppService.CreateAsync(new TenantCreateDto { Name = tenancyName }); |
||||
|
tenant.Name.ShouldBe(tenancyName); |
||||
|
tenant.Id.ShouldNotBe(default(Guid)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CreateAsync_Should_Not_Allow_Duplicate_Names() |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<UserFriendlyException>(async () => |
||||
|
{ |
||||
|
await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme" }); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task UpdateAsync() |
||||
|
{ |
||||
|
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); |
||||
|
|
||||
|
var result = await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "acme-renamed" }); |
||||
|
result.Id.ShouldBe(acme.Id); |
||||
|
result.Name.ShouldBe("acme-renamed"); |
||||
|
|
||||
|
var acmeUpdated = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Id == acme.Id)); |
||||
|
acmeUpdated.Name.ShouldBe("acme-renamed"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task UpdateAsync_Should_Not_Allow_Duplicate_Names() |
||||
|
{ |
||||
|
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); |
||||
|
|
||||
|
await Assert.ThrowsAsync<UserFriendlyException>(async () => |
||||
|
{ |
||||
|
await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" }); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task DeleteAsync() |
||||
|
{ |
||||
|
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); |
||||
|
|
||||
|
await _tenantAppService.DeleteAsync(acme.Id); |
||||
|
|
||||
|
UsingDbContext(dbContext => |
||||
|
{ |
||||
|
dbContext.Tenants.Any(t => t.Id == acme.Id).ShouldBeFalse(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue