optimizing tenant resolution and routing

This commit is contained in:
Shaun Walker
2021-05-10 17:45:39 -04:00
parent 15b0bed257
commit a5de639d15
85 changed files with 592 additions and 723 deletions

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -19,7 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias");
private string Apiurl => CreateApiUrl("Alias", _siteState.Alias);
public async Task<List<Alias>> GetAliasesAsync()
{
@ -32,10 +32,9 @@ namespace Oqtane.Services
return await GetJsonAsync<Alias>($"{Apiurl}/{aliasId}");
}
public async Task<Alias> GetAliasAsync(string name, DateTime lastSyncDate)
public async Task<Alias> GetAliasAsync(string path, DateTime lastSyncDate)
{
name = (string.IsNullOrEmpty(name)) ? "~" : name;
return await GetJsonAsync<Alias>($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
return await GetJsonAsync<Alias>($"{Apiurl}/name/?path={WebUtility.UrlEncode(path)}&sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
}
public async Task<Alias> AddAliasAsync(Alias alias)

View File

@ -21,7 +21,7 @@ namespace Oqtane.Services
_jsRuntime = jsRuntime;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "File");
private string Apiurl => CreateApiUrl("File", _siteState.Alias);
public async Task<List<File>> GetFilesAsync(int folderId)
{

View File

@ -19,7 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, "Folder");
private string ApiUrl => CreateApiUrl("Folder", _siteState.Alias);
public async Task<List<Folder>> GetFoldersAsync(int siteId)
{

View File

@ -7,9 +7,14 @@ namespace Oqtane.Services
{
public class InstallationService : ServiceBase, IInstallationService
{
public InstallationService(HttpClient http):base(http) { }
private readonly SiteState _siteState;
private string ApiUrl => CreateApiUrl("Installation");
public InstallationService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl("Installation", _siteState.Alias);
public async Task<Installation> IsInstalled()
{

View File

@ -1,4 +1,5 @@
using Oqtane.Models;
using Oqtane.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -6,8 +7,6 @@ namespace Oqtane.Services
{
public interface ISiteService
{
void SetAlias(Alias alias);
Task<List<Site>> GetSitesAsync();
Task<Site> GetSiteAsync(int siteId);
@ -17,5 +16,8 @@ namespace Oqtane.Services
Task<Site> UpdateSiteAsync(Site site);
Task DeleteSiteAsync(int siteId);
[Obsolete("This method is deprecated.", false)]
void SetAlias(Alias alias);
}
}

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog");
private string Apiurl => CreateApiUrl("JobLog", _siteState.Alias);
public async Task<List<JobLog>> GetJobLogsAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Job");
private string Apiurl => CreateApiUrl("Job", _siteState.Alias);
public async Task<List<Job>> GetJobsAsync()
{

View File

@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Language");
private string Apiurl => CreateApiUrl("Language", _siteState.Alias);
public async Task<List<Language>> GetLanguagesAsync(int siteId)
{

View File

@ -15,7 +15,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Localization");
private string Apiurl => CreateApiUrl("Localization", _siteState.Alias);
public async Task<IEnumerable<Culture>> GetCulturesAsync() => await GetJsonAsync<IEnumerable<Culture>>(Apiurl);
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
@ -23,7 +23,7 @@ namespace Oqtane.Services
_navigationManager = navigationManager;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Log");
private string Apiurl => CreateApiUrl("Log", _siteState.Alias);
public async Task<List<Log>> GetLogsAsync(int siteId, string level, string function, int rows)
{
@ -49,7 +49,6 @@ namespace Oqtane.Services
}
else
{
base.Alias = alias;
log.SiteId = alias.SiteId;
}
log.PageId = pageId;

View File

@ -21,7 +21,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "ModuleDefinition");
private string Apiurl => CreateApiUrl("ModuleDefinition", _siteState.Alias);
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Module");
private string Apiurl => CreateApiUrl("Module", _siteState.Alias);
public async Task<List<Module>> GetModulesAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using Oqtane.Shared;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Notification");
private string Apiurl => CreateApiUrl("Notification", _siteState.Alias);
public async Task<List<Notification>> GetNotificationsAsync(int siteId, string direction, int userId)
{

View File

@ -3,14 +3,19 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class PackageService : ServiceBase, IPackageService
{
public PackageService(HttpClient http) : base(http) { }
{
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("Package");
public PackageService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("Package", _siteState.Alias);
public async Task<List<Package>> GetPackagesAsync(string tag)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Net.Http;
using System.Threading.Tasks;
using Oqtane.Shared;
@ -15,7 +15,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "PageModule");
private string Apiurl => CreateApiUrl("PageModule", _siteState.Alias);
public async Task<PageModule> GetPageModuleAsync(int pageModuleId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Linq;
using System.Net.Http;
@ -20,7 +20,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Page");
private string Apiurl => CreateApiUrl("Page", _siteState.Alias);
public async Task<List<Page>> GetPagesAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Profile");
private string Apiurl => CreateApiUrl("Profile", _siteState.Alias);
public async Task<List<Profile>> GetProfilesAsync(int siteId)
{

View File

@ -18,7 +18,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Role");
private string Apiurl => CreateApiUrl("Role", _siteState.Alias);
public async Task<List<Role>> GetRolesAsync(int siteId)
{

View File

@ -5,6 +5,7 @@ using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Services
{
@ -17,6 +18,55 @@ namespace Oqtane.Services
_http = client;
}
public string CreateApiUrl(string serviceName, Alias alias)
{
return CreateApiUrl(serviceName, alias, ControllerRoutes.ApiRoute);
}
public string CreateApiUrl(string serviceName, Alias alias, string routeTemplate)
{
string apiurl = "/";
if (routeTemplate == ControllerRoutes.ApiRoute)
{
if (alias != null && !string.IsNullOrEmpty(alias.Path))
{
// include the alias path for multi-tenant context
apiurl += alias.Path + "/";
}
}
else
{
// legacy support for ControllerRoutes.Default
if (alias != null)
{
// include the alias for multi-tenant context
apiurl += $"{alias.AliasId}/";
}
else
{
// tenant agnostic
apiurl += "~/";
}
}
apiurl += $"api/{serviceName}";
return apiurl;
}
// add entityid parameter to url for custom authorization policy
public string CreateAuthorizationPolicyUrl(string url, int entityId)
{
string qs = "entityid=" + entityId.ToString();
if (url.Contains("?"))
{
return url + "&" + qs;
}
else
{
return url + "?" + qs;
}
}
protected async Task GetAsync(string uri)
{
var response = await _http.GetAsync(uri);
@ -135,61 +185,26 @@ namespace Oqtane.Services
//TODO Missing content JSON validation
}
// create an API Url which is tenant agnostic ( for use during installation )
public string CreateApiUrl(string serviceName)
{
return CreateApiUrl(null, serviceName);
}
// create an API Url which is tenant aware ( for use with repositories )
public string CreateApiUrl(Alias alias, string serviceName)
{
string apiurl = "/";
if (Alias != null)
{
alias = Alias; // override the default alias ( for cross-tenant service calls )
}
if (alias != null)
{
// include the alias for multi-tenant context
apiurl += $"{alias.AliasId}/";
}
else
{
// tenant agnostic
apiurl += "~/";
}
apiurl += $"api/{serviceName}";
return apiurl;
}
// can be used to override the default alias
public Alias Alias { get; set; }
// add entityid parameter to url for custom authorization policy
public string CreateAuthorizationPolicyUrl(string url, int entityId)
{
string qs = "entityid=" + entityId.ToString();
if (url.Contains("?"))
{
return url + "&" + qs;
}
else
{
return url + "?" + qs;
}
}
[Obsolete("This method is obsolete. Use CreateApiUrl(Alias alias, string serviceName) instead.", false)]
public string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{
// only retained for short term backward compatibility
return CreateApiUrl(alias, serviceName);
}
[Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)]
public string CreateApiUrl(string serviceName)
{
return CreateApiUrl(serviceName, null, ControllerRoutes.Default);
}
[Obsolete("This method is deprecated.", false)]
public Alias Alias { get; set; }
[Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)]
public string CreateApiUrl(Alias alias, string serviceName)
{
return CreateApiUrl(serviceName, alias, ControllerRoutes.Default);
}
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
@ -18,7 +18,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Setting");
private string Apiurl => CreateApiUrl("Setting", _siteState.Alias);
public async Task<Dictionary<string, string>> GetTenantSettingsAsync()
{
return await GetSettingsAsync(EntityNames.Tenant, -1);

View File

@ -1,9 +1,10 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using System.Collections.Generic;
using Oqtane.Shared;
using System;
namespace Oqtane.Services
{
@ -18,12 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Site");
public void SetAlias(Alias alias)
{
base.Alias = alias;
}
private string Apiurl => CreateApiUrl("Site", _siteState.Alias);
public async Task<List<Site>> GetSitesAsync()
{
@ -50,5 +46,11 @@ namespace Oqtane.Services
{
await DeleteAsync($"{Apiurl}/{siteId}");
}
[Obsolete("This method is deprecated.", false)]
public void SetAlias(Alias alias)
{
base.Alias = alias;
}
}
}

View File

@ -1,4 +1,5 @@
using Oqtane.Models;
using Oqtane.Models;
using Oqtane.Shared;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@ -8,9 +9,13 @@ namespace Oqtane.Services
{
public class SiteTemplateService : ServiceBase, ISiteTemplateService
{
public SiteTemplateService(HttpClient http) : base(http) { }
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("SiteTemplate");
public SiteTemplateService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("SiteTemplate", _siteState.Alias);
public async Task<List<SiteTemplate>> GetSiteTemplatesAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using Oqtane.Shared;
using System.Net.Http;
using System.Threading.Tasks;
@ -14,7 +14,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Sql");
private string Apiurl => CreateApiUrl("Sql", _siteState.Alias);
public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery)
{

View File

@ -1,14 +1,20 @@
using System.Net.Http;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class SystemService : ServiceBase, ISystemService
{
public SystemService(HttpClient http) : base(http) { }
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("System");
public SystemService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("System", _siteState.Alias);
public async Task<Dictionary<string, string>> GetSystemInfoAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Tenant");
private string Apiurl => CreateApiUrl("Tenant", _siteState.Alias);
public async Task<List<Tenant>> GetTenantsAsync()
{

View File

@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, "Theme");
private string ApiUrl => CreateApiUrl("Theme", _siteState.Alias);
public async Task<List<Theme>> GetThemesAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "UserRole");
private string Apiurl => CreateApiUrl("UserRole", _siteState.Alias);
public async Task<List<UserRole>> GetUserRolesAsync(int siteId)
{

View File

@ -14,7 +14,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "User");
private string Apiurl => CreateApiUrl("User", _siteState.Alias);
public async Task<User> GetUserAsync(int userId, int siteId)
{