performance optimization to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries

This commit is contained in:
sbwalker
2024-07-16 16:21:35 -04:00
parent 98bdfd3dbe
commit 4d26468ede
15 changed files with 145 additions and 72 deletions

View File

@ -6,10 +6,26 @@
{
@if (PageState.RenderMode == RenderModes.Interactive)
{
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" />
<ModuleActionsInteractive PageState="@_moduleActionsPageState" ModuleState="@ModuleState" />
}
else
{
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
<ModuleActionsInteractive PageState="@_moduleActionsPageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
}
}
@code {
private ModuleActionsPageState _moduleActionsPageState;
protected override void OnParametersSet()
{
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
_moduleActionsPageState = new ModuleActionsPageState
{
Alias = PageState.Alias,
Page = PageState.Page,
User = PageState.User,
EditMode = PageState.EditMode
};
}
}

View File

@ -7,9 +7,7 @@ using Oqtane.Models;
using Oqtane.Security;
using Oqtane.Services;
using Oqtane.Shared;
using Oqtane.UI;
using System.Net;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Microsoft.Extensions.Localization;
// ReSharper disable UnassignedGetOnlyAutoProperty
@ -24,7 +22,7 @@ namespace Oqtane.Themes.Controls
[Inject] public IModuleService ModuleService { get; set; }
[Inject] public IStringLocalizer<ModuleActionsBase> Localizer { get; set; }
[Parameter] public PageState PageState { get; set; }
[Parameter] public ModuleActionsPageState PageState { get; set; }
[Parameter] public Module ModuleState { get; set; }
public List<ActionViewModel> Actions;

View File

@ -0,0 +1,12 @@
using Oqtane.Models;
namespace Oqtane.Themes.Controls
{
public class ModuleActionsPageState
{
public Alias Alias { get; set; }
public Page Page { get; set; }
public User User { get; set; }
public bool EditMode { get; set; }
}
}

View File

@ -32,11 +32,11 @@
{
@if (PageState.RenderMode == RenderModes.Interactive)
{
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" />
<ControlPanelInteractive PageState="@_controlPanelPageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" />
}
else
{
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
<ControlPanelInteractive PageState="@_controlPanelPageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
}
}
@ -59,6 +59,7 @@
[Parameter]
public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
private ControlPanelPageState _controlPanelPageState;
private bool _canViewAdminDashboard = false;
private bool _showEditMode = false;
@ -82,6 +83,24 @@
}
}
}
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
_controlPanelPageState = new ControlPanelPageState
{
Alias = PageState.Alias,
Site = new Site
{
DefaultContainerType = PageState.Site.DefaultContainerType,
Settings = PageState.Site.Settings,
Themes = PageState.Site.Themes
},
Page = PageState.Page,
User = PageState.User,
Uri = PageState.Uri,
Route = PageState.Route,
RenderMode = PageState.RenderMode,
Runtime = PageState.Runtime
};
}
private bool CanViewAdminDashboard()

View File

@ -28,7 +28,7 @@
</div>
<div class="@BodyClass">
<div class="container-fluid">
@if (_canViewAdminDashboard)
@if (CanViewAdminDashboard)
{
<div class="row d-flex">
<div class="col">
@ -228,7 +228,7 @@
public SiteState SiteState { get; set; }
[Parameter]
public PageState PageState { get; set; }
public ControlPanelPageState PageState { get; set; }
[Parameter]
public string ButtonClass { get; set; }
@ -248,7 +248,9 @@
[Parameter]
public string LanguageDropdownAlignment { get; set; }
private bool _canViewAdminDashboard = false;
[Parameter]
public bool CanViewAdminDashboard { get; set; }
private bool _deleteConfirmation = false;
private List<string> _categories = new List<string>();
private List<ModuleDefinition> _allModuleDefinitions;
@ -278,44 +280,18 @@
// repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary)
ComponentSiteState.Hydrate(SiteState);
_canViewAdminDashboard = CanViewAdminDashboard();
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
{
LoadSettingsAsync();
_pages?.Clear();
foreach (Page p in PageState.Pages)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
_pages.Add(p);
}
}
_pages = await PageService.GetPagesAsync(PageState.Page.SiteId);
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
_containerType = PageState.Site.DefaultContainerType;
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Page.SiteId);
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
}
}
private bool CanViewAdminDashboard()
{
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
if (admin != null)
{
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
{
return true;
}
}
}
return false;
}
private void CategoryChanged(ChangeEventArgs e)
{
_category = (string)e.Value;
@ -371,7 +347,7 @@
if (_moduleType == "new")
{
Module module = new Module();
module.SiteId = PageState.Site.SiteId;
module.SiteId = PageState.Page.SiteId;
module.PageId = PageState.Page.PageId;
module.ModuleDefinitionName = _moduleDefinitionName;
module.AllPages = false;
@ -384,7 +360,7 @@
{
var module = await ModuleService.GetModuleAsync(int.Parse(_moduleId));
module.ModuleId = 0;
module.SiteId = PageState.Site.SiteId;
module.SiteId = PageState.Page.SiteId;
module.PageId = PageState.Page.PageId;
module.AllPages = false;
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
@ -509,11 +485,11 @@
case "publish":
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
{
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
}
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
{
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
}
break;
case "unpublish":

View File

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System;
using Oqtane.Models;
using Oqtane.UI;
namespace Oqtane.Themes.Controls
{
public class ControlPanelPageState
{
public Alias Alias { get; set; }
public Site Site { get; set; }
public Page Page { get; set; }
public User User { get; set; }
public Uri Uri { get; set; }
public Route Route { get; set; }
public string RenderMode { get; set; }
public Shared.Runtime Runtime { get; set; }
}
}