From b3feda9fd151757e55a2749a35701cf5eb4efb3a Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 19 Jul 2022 10:49:33 -0400 Subject: [PATCH] performance optimization for permissions --- .../Interfaces/IPermissionRepository.cs | 5 +- .../Repository/PageModuleRepository.cs | 10 ++-- .../Repository/PermissionRepository.cs | 56 +++++++++++++++---- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs b/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs index 21c349e4..a5a25464 100644 --- a/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Security.Policy; using Oqtane.Models; // ReSharper disable once CheckNamespace namespace Oqtane.Repository { public interface IPermissionRepository - { +{ IEnumerable GetPermissions(int siteId, string entityName); IEnumerable GetPermissions(string entityName, int entityId); IEnumerable GetPermissions(string entityName, int entityId, string permissionName); diff --git a/Oqtane.Server/Repository/PageModuleRepository.cs b/Oqtane.Server/Repository/PageModuleRepository.cs index 07d39801..a99e49a0 100644 --- a/Oqtane.Server/Repository/PageModuleRepository.cs +++ b/Oqtane.Server/Repository/PageModuleRepository.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; using Oqtane.Models; +using Oqtane.Shared; namespace Oqtane.Repository { @@ -24,7 +25,7 @@ namespace Oqtane.Repository .Where(item => item.Module.SiteId == siteId); if (pagemodules.Any()) { - IEnumerable permissions = _permissions.GetPermissions(pagemodules.FirstOrDefault().Module.SiteId, "Module").ToList(); + IEnumerable permissions = _permissions.GetPermissions(siteId, EntityNames.Module).ToList(); foreach (PageModule pagemodule in pagemodules) { pagemodule.Module.Permissions = permissions.Where(item => item.EntityId == pagemodule.ModuleId).EncodePermissions(); @@ -44,7 +45,8 @@ namespace Oqtane.Repository } if (pagemodules.Any()) { - IEnumerable permissions = _permissions.GetPermissions(pagemodules.FirstOrDefault().Module.SiteId, "Module").ToList(); + var siteId = pagemodules.FirstOrDefault().Module.SiteId; + IEnumerable permissions = _permissions.GetPermissions(siteId, EntityNames.Module).ToList(); foreach (PageModule pagemodule in pagemodules) { pagemodule.Module.Permissions = permissions.Where(item => item.EntityId == pagemodule.ModuleId).EncodePermissions(); @@ -87,7 +89,7 @@ namespace Oqtane.Repository } if (pagemodule != null) { - pagemodule.Module.Permissions = _permissions.GetPermissionString("Module", pagemodule.ModuleId); + pagemodule.Module.Permissions = _permissions.GetPermissionString(EntityNames.Module, pagemodule.ModuleId); } return pagemodule; } @@ -98,7 +100,7 @@ namespace Oqtane.Repository .SingleOrDefault(item => item.PageId == pageId && item.ModuleId == moduleId); if (pagemodule != null) { - pagemodule.Module.Permissions = _permissions.GetPermissionString("Module", pagemodule.ModuleId); + pagemodule.Module.Permissions = _permissions.GetPermissionString(EntityNames.Module, pagemodule.ModuleId); } return pagemodule; } diff --git a/Oqtane.Server/Repository/PermissionRepository.cs b/Oqtane.Server/Repository/PermissionRepository.cs index 7a66b3bf..ed25969e 100644 --- a/Oqtane.Server/Repository/PermissionRepository.cs +++ b/Oqtane.Server/Repository/PermissionRepository.cs @@ -1,11 +1,13 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; +using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; using Oqtane.Models; +using Microsoft.Extensions.Caching.Memory; namespace Oqtane.Repository { @@ -13,33 +15,49 @@ namespace Oqtane.Repository { private TenantDBContext _db; private readonly IRoleRepository _roles; + private readonly IMemoryCache _cache; + private readonly IHttpContextAccessor _accessor; - public PermissionRepository(TenantDBContext context, IRoleRepository roles) + public PermissionRepository(TenantDBContext context, IRoleRepository roles, IMemoryCache cache, IHttpContextAccessor accessor) { _db = context; _roles = roles; + _cache = cache; + _accessor = accessor; } public IEnumerable GetPermissions(int siteId, string entityName) { - return _db.Permission.Where(item => item.SiteId == siteId) - .Where(item => item.EntityName == entityName) - .Include(item => item.Role); // eager load roles + var alias = _accessor.HttpContext.GetAlias(); + if (alias != null) + { + return _cache.GetOrCreate($"permissions:{alias.SiteKey}:{entityName}", entry => + { + entry.SlidingExpiration = TimeSpan.FromMinutes(30); + return _db.Permission.Where(item => item.SiteId == alias.SiteId) + .Where(item => item.EntityName == entityName) + .Include(item => item.Role).ToList(); // eager load roles + }); + } + else + { + return _db.Permission.Where(item => item.SiteId == siteId || siteId == -1) + .Where(item => item.EntityName == entityName) + .Include(item => item.Role).ToList(); // eager load roles + } } public IEnumerable GetPermissions(string entityName, int entityId) { - return _db.Permission.Where(item => item.EntityName == entityName) - .Where(item => item.EntityId == entityId) - .Include(item => item.Role); // eager load roles + var permissions = GetPermissions(-1, entityName); + return permissions.Where(item => item.EntityId == entityId); } public IEnumerable GetPermissions(string entityName, int entityId, string permissionName) { - return _db.Permission.Where(item => item.EntityName == entityName) - .Where(item => item.EntityId == entityId) - .Where(item => item.PermissionName == permissionName) - .Include(item => item.Role); // eager load roles + var permissions = GetPermissions(-1, entityName); + return permissions.Where(item => item.EntityId == entityId) + .Where(item => item.PermissionName == permissionName); } public string GetPermissionString(int siteId, string entityName) @@ -62,6 +80,7 @@ namespace Oqtane.Repository { _db.Permission.Add(permission); _db.SaveChanges(); + ClearCache(permission.EntityName); return permission; } @@ -69,6 +88,7 @@ namespace Oqtane.Repository { _db.Entry(permission).State = EntityState.Modified; _db.SaveChanges(); + ClearCache(permission.EntityName); return permission; } @@ -90,6 +110,7 @@ namespace Oqtane.Repository _db.Permission.Add(permission); } _db.SaveChanges(); + ClearCache(entityName); } public Permission GetPermission(int permissionId) @@ -102,6 +123,7 @@ namespace Oqtane.Repository Permission permission = _db.Permission.Find(permissionId); _db.Permission.Remove(permission); _db.SaveChanges(); + ClearCache(permission.EntityName); } public void DeletePermissions(int siteId, string entityName, int entityId) @@ -115,6 +137,16 @@ namespace Oqtane.Repository _db.Permission.Remove(permission); } _db.SaveChanges(); + ClearCache(entityName); + } + + private void ClearCache(string entityName) + { + var alias = _accessor.HttpContext.GetAlias(); + if (alias != null) + { + _cache.Remove($"permissions:{alias.SiteKey}:{entityName}"); + } } // permissions are stored in the format "{permissionname:!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]}" where "!" designates Deny permissions