mirror of https://github.com/abpframework/abp.git
committed by
GitHub
13 changed files with 314 additions and 62 deletions
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
public interface IMultiTenantUrlProvider |
||||
|
{ |
||||
|
Task<string> GetUrlAsync(string templateUrl); |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
public class MultiTenantUrlProvider : IMultiTenantUrlProvider , ITransientDependency |
||||
|
{ |
||||
|
public const string TenantPlaceHolder = "{0}"; |
||||
|
public const string TenantIdPlaceHolder = "{{tenantId}}"; |
||||
|
public const string TenantNamePlaceHolder = "{{tenantName}}"; |
||||
|
|
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
protected ITenantStore TenantStore { get; } |
||||
|
|
||||
|
public MultiTenantUrlProvider( |
||||
|
ICurrentTenant currentTenant, |
||||
|
ITenantStore tenantStore) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
TenantStore = tenantStore; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<string> GetUrlAsync(string templateUrl) |
||||
|
{ |
||||
|
return await ReplacePlaceHoldersAsync(templateUrl); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> ReplacePlaceHoldersAsync(string templateUrl) |
||||
|
{ |
||||
|
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantIdPlaceHolder); |
||||
|
|
||||
|
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantNamePlaceHolder); |
||||
|
|
||||
|
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantPlaceHolder); |
||||
|
|
||||
|
return templateUrl; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> ReplacePlaceHolderAsync(string templateUrl, string placeHolder) |
||||
|
{ |
||||
|
if (!templateUrl.Contains(placeHolder)) |
||||
|
{ |
||||
|
return templateUrl; |
||||
|
} |
||||
|
|
||||
|
var placeHolderValue = string.Empty; |
||||
|
if (CurrentTenant.IsAvailable) |
||||
|
{ |
||||
|
placeHolderValue = (placeHolder == TenantIdPlaceHolder ? CurrentTenant.Id!.Value.ToString() : await GetCurrentTenantNameAsync()) + "."; |
||||
|
} |
||||
|
|
||||
|
if (templateUrl.Contains(placeHolder + '.')) |
||||
|
{ |
||||
|
placeHolder += '.'; |
||||
|
} |
||||
|
|
||||
|
templateUrl = templateUrl.Replace( |
||||
|
placeHolder, |
||||
|
placeHolderValue |
||||
|
); |
||||
|
|
||||
|
return templateUrl; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> GetCurrentTenantNameAsync() |
||||
|
{ |
||||
|
if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty()) |
||||
|
{ |
||||
|
var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value); |
||||
|
return tenantConfiguration!.Name; |
||||
|
} |
||||
|
|
||||
|
return CurrentTenant.Name!; |
||||
|
} |
||||
|
} |
||||
@ -1,25 +1,54 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Microsoft.Extensions.Options; |
using Microsoft.Extensions.Options; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
namespace Volo.Abp.Http.Client; |
namespace Volo.Abp.Http.Client; |
||||
|
|
||||
public class RemoteServiceConfigurationProvider : IRemoteServiceConfigurationProvider, IScopedDependency |
public class RemoteServiceConfigurationProvider : IRemoteServiceConfigurationProvider, IScopedDependency |
||||
{ |
{ |
||||
protected AbpRemoteServiceOptions Options { get; } |
protected AbpRemoteServiceOptions Options { get; } |
||||
|
protected IMultiTenantUrlProvider MultiTenantUrlProvider { get; } |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
|
||||
public RemoteServiceConfigurationProvider(IOptionsMonitor<AbpRemoteServiceOptions> options) |
public RemoteServiceConfigurationProvider( |
||||
|
IOptionsMonitor<AbpRemoteServiceOptions> options, |
||||
|
IMultiTenantUrlProvider multiTenantUrlProvider, |
||||
|
ICurrentTenant currentTenant) |
||||
{ |
{ |
||||
|
MultiTenantUrlProvider = multiTenantUrlProvider; |
||||
|
CurrentTenant = currentTenant; |
||||
Options = options.CurrentValue; |
Options = options.CurrentValue; |
||||
} |
} |
||||
|
|
||||
public Task<RemoteServiceConfiguration> GetConfigurationOrDefaultAsync(string name) |
public virtual async Task<RemoteServiceConfiguration> GetConfigurationOrDefaultAsync(string name) |
||||
{ |
{ |
||||
return Task.FromResult(Options.RemoteServices.GetConfigurationOrDefault(name)); |
return (await GetMultiTenantConfigurationAsync(Options.RemoteServices.GetConfigurationOrDefault(name)))!; |
||||
} |
} |
||||
|
|
||||
public Task<RemoteServiceConfiguration?> GetConfigurationOrDefaultOrNullAsync(string name) |
public virtual async Task<RemoteServiceConfiguration?> GetConfigurationOrDefaultOrNullAsync(string name) |
||||
{ |
{ |
||||
return Task.FromResult(Options.RemoteServices.GetConfigurationOrDefaultOrNull(name)); |
return await GetMultiTenantConfigurationAsync(Options.RemoteServices.GetConfigurationOrDefaultOrNull(name)); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<RemoteServiceConfiguration?> GetMultiTenantConfigurationAsync(RemoteServiceConfiguration? configuration) |
||||
|
{ |
||||
|
if (configuration == null) |
||||
|
{ |
||||
|
return configuration; |
||||
|
} |
||||
|
|
||||
|
var baseUrl = await MultiTenantUrlProvider.GetUrlAsync(configuration.BaseUrl); |
||||
|
if (baseUrl == configuration.BaseUrl) |
||||
|
{ |
||||
|
return configuration; |
||||
|
} |
||||
|
|
||||
|
var multiTenantConfiguration = new RemoteServiceConfiguration(configuration) |
||||
|
{ |
||||
|
BaseUrl = baseUrl |
||||
|
}; |
||||
|
|
||||
|
return multiTenantConfiguration; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,57 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.MultiTenancy.ConfigurationStore; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
public class MultiTenantUrlProivder_Tests : MultiTenancyTestBase |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly IMultiTenantUrlProvider _multiTenantUrlProvider; |
||||
|
|
||||
|
private readonly Guid _tenantAId = Guid.NewGuid(); |
||||
|
|
||||
|
public MultiTenantUrlProivder_Tests() |
||||
|
{ |
||||
|
_currentTenant = ServiceProvider.GetRequiredService<ICurrentTenant>(); |
||||
|
_multiTenantUrlProvider = ServiceProvider.GetRequiredService<IMultiTenantUrlProvider>(); |
||||
|
} |
||||
|
protected override void BeforeAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
services.Configure<AbpDefaultTenantStoreOptions>(options => |
||||
|
{ |
||||
|
options.Tenants = |
||||
|
[ |
||||
|
new TenantConfiguration(_tenantAId, "TenantA") |
||||
|
]; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetUrlAsync() |
||||
|
{ |
||||
|
var tenantNameHolderUrl = "https://{{tenantName}}.abp.io"; |
||||
|
var tenantIdHolderUrl = "https://{{tenantId}}.abp.io"; |
||||
|
var tenantHolderUrl = "https://{0}.abp.io"; |
||||
|
var hostUrl = "https://abp.io"; |
||||
|
|
||||
|
_currentTenant.Id.ShouldBeNull(); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantNameHolderUrl)).ShouldBe(hostUrl); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantIdHolderUrl)).ShouldBe(hostUrl); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantHolderUrl)).ShouldBe(hostUrl); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(hostUrl)).ShouldBe(hostUrl); |
||||
|
|
||||
|
using (_currentTenant.Change(_tenantAId)) |
||||
|
{ |
||||
|
_currentTenant.Id.ShouldBe(_tenantAId); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantNameHolderUrl)).ShouldBe("https://TenantA.abp.io"); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantIdHolderUrl)).ShouldBe("https://"+_tenantAId+".abp.io"); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(tenantHolderUrl)).ShouldBe("https://TenantA.abp.io"); |
||||
|
(await _multiTenantUrlProvider.GetUrlAsync(hostUrl)).ShouldBe(hostUrl); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net8.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.RemoteServices\Volo.Abp.RemoteServices.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client; |
||||
|
|
||||
|
public abstract class AbpRemoteServicesTestBase : AbpIntegratedTest<AbpRemoteServicesTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.RemoteServices; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpMultiTenancyModule), |
||||
|
typeof(AbpRemoteServicesModule) |
||||
|
)] |
||||
|
public class AbpRemoteServicesTestModule: AbpModule |
||||
|
{ |
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.MultiTenancy.ConfigurationStore; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client; |
||||
|
|
||||
|
public class RemoteServiceConfigurationProvider_Tests : AbpRemoteServicesTestBase |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly IRemoteServiceConfigurationProvider _remoteServiceConfigurationProvider; |
||||
|
private readonly Guid _tenantAId = Guid.NewGuid(); |
||||
|
|
||||
|
public RemoteServiceConfigurationProvider_Tests() |
||||
|
{ |
||||
|
_currentTenant = GetRequiredService<ICurrentTenant>(); |
||||
|
_remoteServiceConfigurationProvider = GetRequiredService<IRemoteServiceConfigurationProvider>(); |
||||
|
} |
||||
|
|
||||
|
protected override void AfterAddApplication(IServiceCollection services) |
||||
|
{ |
||||
|
services.Configure<AbpRemoteServiceOptions>(options => |
||||
|
{ |
||||
|
options.RemoteServices[RemoteServiceConfigurationDictionary.DefaultName] = new RemoteServiceConfiguration("https://abp.io"); |
||||
|
options.RemoteServices["Identity"] = new RemoteServiceConfiguration("https://{{tenantName}}.abp.io"); |
||||
|
options.RemoteServices["Permission"] = new RemoteServiceConfiguration("https://{{tenantId}}.abp.io"); |
||||
|
options.RemoteServices["Setting"] = new RemoteServiceConfiguration("https://{0}.abp.io"); |
||||
|
}); |
||||
|
|
||||
|
services.Configure<AbpDefaultTenantStoreOptions>(options => |
||||
|
{ |
||||
|
options.Tenants = |
||||
|
[ |
||||
|
new TenantConfiguration(_tenantAId, "TenantA") |
||||
|
]; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetConfigurationOrDefaultAsync() |
||||
|
{ |
||||
|
_currentTenant.Id.ShouldBeNull(); |
||||
|
|
||||
|
var defaultConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(RemoteServiceConfigurationDictionary.DefaultName); |
||||
|
defaultConfiguration.BaseUrl.ShouldBe("https://abp.io"); |
||||
|
|
||||
|
var identityConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Identity"); |
||||
|
identityConfiguration.BaseUrl.ShouldBe("https://abp.io"); |
||||
|
|
||||
|
var permissionConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Permission"); |
||||
|
permissionConfiguration.BaseUrl.ShouldBe("https://abp.io"); |
||||
|
|
||||
|
var settingConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Setting"); |
||||
|
settingConfiguration.BaseUrl.ShouldBe("https://abp.io"); |
||||
|
|
||||
|
using (_currentTenant.Change(_tenantAId, "TenantA")) |
||||
|
{ |
||||
|
defaultConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(RemoteServiceConfigurationDictionary.DefaultName); |
||||
|
defaultConfiguration.BaseUrl.ShouldBe("https://abp.io"); |
||||
|
|
||||
|
identityConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Identity"); |
||||
|
identityConfiguration.BaseUrl.ShouldBe($"https://{_currentTenant.Name}.abp.io"); |
||||
|
|
||||
|
permissionConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Permission"); |
||||
|
permissionConfiguration.BaseUrl.ShouldBe($"https://{_currentTenant.Id}.abp.io"); |
||||
|
|
||||
|
settingConfiguration = await _remoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Setting"); |
||||
|
settingConfiguration.BaseUrl.ShouldBe($"https://{_currentTenant.Name}.abp.io"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue