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

@ -55,17 +55,28 @@ namespace Oqtane.Repository
List<Alias> aliases = GetAliases().ToList();
var segments = name.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// iterate segments in reverse order
for (int i = segments.Length; i > 0; i--)
// iterate segments to find keywords
int start = segments.Length;
for (int i = 0; i < segments.Length; i++)
{
name = string.Join("/", segments, 0, i);
alias = aliases.Find(item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
if (segments[i] == "api" || segments[i] == "pages" || segments[i] == "*")
{
start = i;
break;
}
}
// iterate segments in reverse order to find alias match
for (int i = start; i > 0; i--)
{
alias = aliases.Find(item => item.Name.Equals(string.Join("/", segments, 0, i), StringComparison.OrdinalIgnoreCase));
if (alias != null)
{
break; // found a matching alias
}
}
// return fallback alias
// return fallback alias if none found
return alias ?? aliases.Find(item => item.Name.Equals("*"));
}

View File

@ -8,9 +8,10 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Oqtane.Extensions;
using Oqtane.Infrastructure;
using Oqtane.Interfaces;
using Oqtane.Migrations.Framework;
using Oqtane.Repository.Databases.Interfaces;
using Oqtane.Models;
using Oqtane.Shared;
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
@ -20,26 +21,27 @@ namespace Oqtane.Repository
public class DBContextBase : IdentityUserContext<IdentityUser>
{
private readonly ITenantResolver _tenantResolver;
private readonly ITenantManager _tenantManager;
private readonly IHttpContextAccessor _accessor;
private readonly IConfiguration _configuration;
private string _connectionString;
private string _databaseType;
public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor)
public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor)
{
_connectionString = String.Empty;
_tenantResolver = tenantResolver;
_tenantManager = tenantManager;
_accessor = httpContextAccessor;
}
public DBContextBase(IDbConfig dbConfig, ITenantResolver tenantResolver)
public DBContextBase(IDbConfig dbConfig, ITenantManager tenantManager)
{
_accessor = dbConfig.Accessor;
_configuration = dbConfig.Configuration;
_connectionString = dbConfig.ConnectionString;
_databaseType = dbConfig.DatabaseType;
Databases = dbConfig.Databases;
_tenantResolver = tenantResolver;
_tenantManager = tenantManager;
}
public IEnumerable<IOqtaneDatabase> Databases { get; }
@ -48,9 +50,18 @@ namespace Oqtane.Repository
{
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
if (string.IsNullOrEmpty(_connectionString) && _tenantResolver != null)
if (string.IsNullOrEmpty(_connectionString))
{
var tenant = _tenantResolver.GetTenant();
Tenant tenant;
if (_tenantResolver != null)
{
tenant = _tenantResolver.GetTenant();
}
else
{
tenant = _tenantManager.GetTenant();
}
if (tenant != null)
{
@ -103,5 +114,25 @@ namespace Oqtane.Repository
return base.SaveChanges();
}
[Obsolete("This constructor is obsolete. Use DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) instead.", false)]
public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor)
{
_connectionString = String.Empty;
_tenantResolver = tenantResolver;
_accessor = httpContextAccessor;
}
[Obsolete("This constructor is obsolete. Use DBContextBase(IDbConfig dbConfig, ITenantManager tenantManager) instead.", false)]
public DBContextBase(IDbConfig dbConfig, ITenantResolver tenantResolver)
{
_accessor = dbConfig.Accessor;
_configuration = dbConfig.Configuration;
_connectionString = dbConfig.ConnectionString;
_databaseType = dbConfig.DatabaseType;
Databases = dbConfig.Databases;
_tenantResolver = tenantResolver;
}
}
}

View File

@ -1,6 +1,5 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Oqtane.Interfaces;
using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Repository.Databases.Interfaces;
@ -12,7 +11,7 @@ namespace Oqtane.Repository
{
public class TenantDBContext : DBContextBase, IMultiDatabase
{
public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) { }
public TenantDBContext(IDbConfig dbConfig, ITenantManager tenantManager) : base(dbConfig, tenantManager) { }
public virtual DbSet<Site> Site { get; set; }
public virtual DbSet<Page> Page { get; set; }

View File

@ -1,7 +1,8 @@
using Oqtane.Models;
using Oqtane.Models;
namespace Oqtane.Repository
{
// class deprecated and replaced by ITenantManager
public interface ITenantResolver
{
Alias GetAlias();

View File

@ -1,78 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Repository
{
// class deprecated and replaced by ITenantManager
public class TenantResolver : ITenantResolver
{
private readonly IHttpContextAccessor _accessor;
private readonly IAliasRepository _aliasRepository;
private readonly ITenantRepository _tenantRepository;
private readonly SiteState _siteState;
private readonly ITenantManager _tenantManager;
private Alias _alias;
private Tenant _tenant;
public TenantResolver(IHttpContextAccessor accessor, IAliasRepository aliasRepository, ITenantRepository tenantRepository, SiteState siteState)
public TenantResolver(ITenantManager tenantManager)
{
_accessor = accessor;
_aliasRepository = aliasRepository;
_tenantRepository = tenantRepository;
_siteState = siteState;
_tenantManager = tenantManager;
}
public Alias GetAlias()
{
if (_alias == null) ResolveTenant();
return _alias;
return _tenantManager.GetAlias();
}
public Tenant GetTenant()
{
if (_tenant == null) ResolveTenant();
return _tenant;
}
private void ResolveTenant()
{
if (_siteState != null && _siteState.Alias != null)
{
// background processes can pass in an alias using the SiteState service
_alias = _siteState.Alias;
}
else
{
int aliasId = -1;
// get aliasid identifier based on request
if (_accessor.HttpContext != null)
{
string[] segments = _accessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if (segments.Length > 1 && (segments[1] == "api" || segments[1] == "pages") && segments[0] != "~")
{
aliasId = int.Parse(segments[0]);
}
}
// get the alias
IEnumerable<Alias> aliases = _aliasRepository.GetAliases().ToList(); // cached
if (aliasId != -1)
{
_alias = aliases.FirstOrDefault(item => item.AliasId == aliasId);
}
}
if (_alias != null)
{
// get the tenant
IEnumerable<Tenant> tenants = _tenantRepository.GetTenants(); // cached
_tenant = tenants.FirstOrDefault(item => item.TenantId == _alias.TenantId);
}
return _tenantManager.GetTenant();
}
}
}