diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs index 4865489248..6c44195b1a 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs @@ -1,13 +1,12 @@ -using JetBrains.Annotations; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy { + [Dependency(ReplaceServices = true)] public class HttpContextTenantResolveResultAccessor : ITenantResolveResultAccessor, ITransientDependency { - [CanBeNull] public TenantResolveResult Result { get diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/ITenantResolveResultAccessor.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantResolveResultAccessor.cs similarity index 58% rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/ITenantResolveResultAccessor.cs rename to framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantResolveResultAccessor.cs index 90201dcf2d..f8acb22538 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/ITenantResolveResultAccessor.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantResolveResultAccessor.cs @@ -1,9 +1,10 @@ -using Volo.Abp.MultiTenancy; +using JetBrains.Annotations; -namespace Volo.Abp.AspNetCore.MultiTenancy +namespace Volo.Abp.MultiTenancy { public interface ITenantResolveResultAccessor { + [CanBeNull] TenantResolveResult Result { get; set; } } } diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/NullTenantResolveResultAccessor.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/NullTenantResolveResultAccessor.cs new file mode 100644 index 0000000000..b97ab2c518 --- /dev/null +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/NullTenantResolveResultAccessor.cs @@ -0,0 +1,13 @@ +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.MultiTenancy +{ + public class NullTenantResolveResultAccessor : ITenantResolveResultAccessor, ISingletonDependency + { + public TenantResolveResult Result + { + get => null; + set { } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs index e46bac2c66..1c6065adea 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs @@ -1,6 +1,4 @@ -using Volo.Abp.Ui.Navigation.Urls; - -namespace Volo.Abp.Ui.Navigation.Urls +namespace Volo.Abp.Ui.Navigation.Urls { public class AppUrlOptions { diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs index f55b741579..e6a5747ae2 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs @@ -1,20 +1,42 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Ui.Navigation.Urls { public class AppUrlProvider : IAppUrlProvider, ITransientDependency { + public const string TenantIdPlaceHolder = "{{tenantId}}"; + public const string TenantNamePlaceHolder = "{{tenantName}}"; + protected AppUrlOptions Options { get; } + protected ICurrentTenant CurrentTenant { get; } + protected ITenantStore TenantStore { get; } - public AppUrlProvider(IOptions options) + public AppUrlProvider( + IOptions options, + ICurrentTenant currentTenant, + ITenantStore tenantStore) { + CurrentTenant = currentTenant; + TenantStore = tenantStore; Options = options.Value; } - public virtual string GetUrl(string appName, string urlName = null) + public virtual async Task GetUrlAsync(string appName, string urlName = null) + { + return await ReplacePlaceHoldersAsync( + await GetConfiguredUrl( + appName, + urlName + ) + ); + } + + protected virtual Task GetConfiguredUrl(string appName, string urlName) { var app = Options.Applications[appName]; @@ -22,24 +44,70 @@ namespace Volo.Abp.Ui.Navigation.Urls { if (app.RootUrl.IsNullOrEmpty()) { - throw new AbpException($"RootUrl for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!"); + throw new AbpException( + $"RootUrl for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!" + ); } - return app.RootUrl; + return Task.FromResult(app.RootUrl); } var url = app.Urls.GetOrDefault(urlName); if (url.IsNullOrEmpty()) { - throw new AbpException($"Url, named '{urlName}', for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!"); + throw new AbpException( + $"Url, named '{urlName}', for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!" + ); } if (app.RootUrl == null) + { + return Task.FromResult(url); + } + + return Task.FromResult(app.RootUrl.EnsureEndsWith('/') + url); + } + + protected virtual async Task ReplacePlaceHoldersAsync(string url) + { + url = url.Replace( + TenantIdPlaceHolder, + CurrentTenant.Id.HasValue ? CurrentTenant.Id.Value.ToString() : "" + ); + + if (!url.Contains(TenantNamePlaceHolder)) { return url; } - return app.RootUrl.EnsureEndsWith('/') + url; + var tenantNamePlaceHolder = TenantNamePlaceHolder; + + if (url.Contains(TenantNamePlaceHolder + '.')) + { + tenantNamePlaceHolder = TenantNamePlaceHolder + '.'; + } + + if (CurrentTenant.Id.HasValue) + { + url = url.Replace(tenantNamePlaceHolder, await GetCurrentTenantNameAsync()); + } + else + { + url = url.Replace(tenantNamePlaceHolder, ""); + } + + return url; + } + + private async Task GetCurrentTenantNameAsync() + { + if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty()) + { + var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value); + return tenantConfiguration.Name; + } + + return CurrentTenant.Name; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs index ac7ce1abd5..325117a24e 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs @@ -1,9 +1,10 @@ -using JetBrains.Annotations; +using System.Threading.Tasks; +using JetBrains.Annotations; namespace Volo.Abp.Ui.Navigation.Urls { public interface IAppUrlProvider { - string GetUrl([NotNull] string appName, [CanBeNull] string urlName = null); + Task GetUrlAsync([NotNull] string appName, [CanBeNull] string urlName = null); } }