Performance improvements, refactoring of multi-tenant support, split Alias and Tenant entities for cleaner separation of concerns, create an additional site during installation for demonstratng multitenancy

This commit is contained in:
Shaun Walker
2019-05-24 13:33:19 -04:00
parent 0067521cd5
commit 8deb119f36
57 changed files with 880 additions and 309 deletions

View File

@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
namespace Oqtane.Repository
{
public class AliasRepository : IAliasRepository
{
private HostContext db;
private readonly IMemoryCache _cache;
public AliasRepository(HostContext context, IMemoryCache cache)
{
db = context;
_cache = cache;
}
public IEnumerable<Alias> GetAliases()
{
try
{
IEnumerable<Alias> aliases = _cache.GetOrCreate("aliases", entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
return db.Alias.ToList();
});
return aliases;
}
catch
{
throw;
}
}
public void AddAlias(Alias alias)
{
try
{
db.Alias.Add(alias);
db.SaveChanges();
}
catch
{
throw;
}
}
public void UpdateAlias(Alias alias)
{
try
{
db.Entry(alias).State = EntityState.Modified;
db.SaveChanges();
}
catch
{
throw;
}
}
public Alias GetAlias(int aliasId)
{
try
{
Alias alias = db.Alias.Find(aliasId);
return alias;
}
catch
{
throw;
}
}
public void DeleteAlias(int aliasId)
{
try
{
Alias alias = db.Alias.Find(aliasId);
db.Alias.Remove(alias);
db.SaveChanges();
}
catch
{
throw;
}
}
}
}

View File

@ -8,9 +8,9 @@ namespace Oqtane.Repository
{
private Tenant tenant;
public ContextBase(ITenantRepository TenantRepository)
public ContextBase(ITenantResolver TenantResolver)
{
tenant = TenantRepository.GetTenant();
tenant = TenantResolver.GetTenant();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@ -7,6 +7,7 @@ namespace Oqtane.Repository
{
public HostContext(DbContextOptions<HostContext> options) : base(options) { }
public virtual DbSet<Alias> Alias { get; set; }
public virtual DbSet<Tenant> Tenant { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using Oqtane.Models;
namespace Oqtane.Repository
{
public interface IAliasRepository
{
IEnumerable<Alias> GetAliases();
void AddAlias(Alias alias);
void UpdateAlias(Alias alias);
Alias GetAlias(int aliasId);
void DeleteAlias(int aliasId);
}
}

View File

@ -1,9 +1,14 @@
using Oqtane.Models;
using System.Collections.Generic;
namespace Oqtane.Repository
{
public interface ITenantRepository
{
Tenant GetTenant();
IEnumerable<Tenant> GetTenants();
void AddTenant(Tenant tenant);
void UpdateTenant(Tenant tenant);
Tenant GetTenant(int tenantId);
void DeleteTenant(int tenantId);
}
}

View File

@ -0,0 +1,9 @@
using Oqtane.Models;
namespace Oqtane.Repository
{
public interface ITenantResolver
{
Tenant GetTenant();
}
}

View File

@ -14,9 +14,9 @@ namespace Oqtane.Repository
private readonly Tenant tenant;
public TenantContext(ITenantRepository TenantRepository)
public TenantContext(ITenantResolver TenantResolver)
{
tenant = TenantRepository.GetTenant();
tenant = TenantResolver.GetTenant();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@ -4,6 +4,7 @@ using System.Linq;
using Oqtane.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.EntityFrameworkCore;
namespace Oqtane.Repository
{
@ -11,23 +12,14 @@ namespace Oqtane.Repository
{
private HostContext db;
private readonly IMemoryCache _cache;
private readonly string alias;
public TenantRepository(HostContext context, IMemoryCache cache, IHttpContextAccessor accessor)
public TenantRepository(HostContext context, IMemoryCache cache)
{
db = context;
_cache = cache;
// get site alias based on request context
alias = accessor.HttpContext.Request.Host.Value;
string path = accessor.HttpContext.Request.Path.Value;
if (path.StartsWith("/~") && !path.StartsWith("/~/"))
{
alias += path.Substring(0, path.IndexOf("/", 1));
}
}
public Tenant GetTenant()
public IEnumerable<Tenant> GetTenants()
{
try
{
@ -36,15 +28,45 @@ namespace Oqtane.Repository
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
return db.Tenant.ToList();
});
Tenant tenant;
if (tenants.Count() == 1)
{
tenant = tenants.FirstOrDefault();
}
else
{
tenant = tenants.Where(item => item.Alias == alias).FirstOrDefault();
}
return tenants;
}
catch
{
throw;
}
}
public void AddTenant(Tenant tenant)
{
try
{
db.Tenant.Add(tenant);
db.SaveChanges();
}
catch
{
throw;
}
}
public void UpdateTenant(Tenant tenant)
{
try
{
db.Entry(tenant).State = EntityState.Modified;
db.SaveChanges();
}
catch
{
throw;
}
}
public Tenant GetTenant(int tenantId)
{
try
{
Tenant tenant = db.Tenant.Find(tenantId);
return tenant;
}
catch
@ -52,5 +74,19 @@ namespace Oqtane.Repository
throw;
}
}
public void DeleteTenant(int tenantId)
{
try
{
Tenant tenant = db.Tenant.Find(tenantId);
db.Tenant.Remove(tenant);
db.SaveChanges();
}
catch
{
throw;
}
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
namespace Oqtane.Repository
{
public class TenantResolver : ITenantResolver
{
private HostContext db;
private readonly string aliasname;
private readonly IAliasRepository _aliasrepository;
private readonly ITenantRepository _tenantrepository;
public TenantResolver(HostContext context, IHttpContextAccessor accessor, IAliasRepository aliasrepository, ITenantRepository tenantrepository)
{
db = context;
_aliasrepository = aliasrepository;
_tenantrepository = tenantrepository;
// get alias based on request context
aliasname = accessor.HttpContext.Request.Host.Value;
string path = accessor.HttpContext.Request.Path.Value;
string[] segments = path.Split('/');
if (segments[1] != "~")
{
aliasname += "/" + segments[1];
}
}
public Tenant GetTenant()
{
try
{
IEnumerable<Alias> aliases = _aliasrepository.GetAliases(); // cached
Alias alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault();
IEnumerable<Tenant> tenants = _tenantrepository.GetTenants(); // cached
return tenants.Where(item => item.TenantId == alias.TenantId).FirstOrDefault();
}
catch
{
throw;
}
}
}
}