Save and reload grid or dropdownlist blazor control state to remember user's changes over page refresh

When user makes changes to his screen like changing sort order or columns of datagrid or moves to a certain page then he automatically wants to keep these settings in his profile so that he does not lose them when he moves to another page and then comes back. This post shows a possibilty how this can be achieved. State data is serialized and then saved in an additional field in table AspNetUsers.

First, datagrid is extended with property @bind-settings with value @Settings

Settings property is defined in partial class page.razor.cs

        DataGridSettings _settings;
        public DataGridSettings Settings
        {
            get
            {
                return _settings;
            }
            set
            {
                if (_settings != value)
                {
                    _settings = value;
                    InvokeAsync(SaveStateAsync);
                }
            }
        }

To handle settings data we use a class called ApplicationUserState.cs

using Microsoft.AspNetCore.Components;
using Microsoft.VisualStudio.Services.Common;
using Projektabrechnung.Models.EEvolution;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

namespace Projektabrechnung.Models
{
    /// <summary>
    /// Klasse zum Speichern eines einzelnen state values
    /// </summary>
    public class ApplicationUserStateValues
    {
        public string PageName
        { get; set; }

        public string ControlName
        { get; set; }

        public string SettingName
        { get; set; }

        public ApplicationUserState.Screentypes ScreenType
        { get; set; }

        public string SettingValue
        { get; set; }

        public DateTime TimeStamp
        { get; set; }
    }

    /// <summary>
    /// Klasse zum Speichern und Selektieren des state im User Datensatz
    /// </summary>
    public class ApplicationUserState
    {

        private SecurityService security;

        public ApplicationUserState()
        { }

        private List<ApplicationUserStateValues> _data;
        public List<ApplicationUserStateValues> Data
        {
            get
            {
                if (_data == null && security.User.ApplicationUserState != null)
                {
                    _data = JsonSerializer.Deserialize<List<ApplicationUserStateValues>>(security.User.ApplicationUserState);
                }

                return _data;

            }
            set
            {
                if (_data != value)
                {
                    _data = value;
                }
            }
        }

        /// <summary>
        /// Retrieves State Data from IEnumerable collection
        /// </summary>
        /// <param name="Security">The security service instance which controls user data</param>
        /// <param name="PageName">Name of the application page</param>
        /// <param name="ControlName">Name of the control inside the page</param>
        /// <param name="ScreenType">Sceentype enumerable value</param>
        /// <param name="SettingName">Name of the Setting</param>
        /// <returns>Value as string</returns>
        public async Task<string> GetData(SecurityService Security, string PageName, string ControlName, Screentypes ScreenType, string SettingName)
        {
            security = Security;

            if (security.User != null && !string.IsNullOrEmpty(PageName) && !string.IsNullOrEmpty(ControlName) && !string.IsNullOrEmpty(SettingName) && Data != null)
            {
                string s = Data.Where(d => d.PageName == PageName && d.ControlName == ControlName && d.ScreenType == Screentypes.Desktop && d.SettingName == SettingName).Select(s => s.SettingValue).FirstOrDefault();
                return s;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Saves State Data to IEnumerable collection
        /// </summary>
        /// <param name="Security">The security service instance which controls user data</param>
        /// <param name="PageName">Name of the application page</param>
        /// <param name="ControlName">Name of the control inside the page</param>
        /// <param name="ScreenType">Sceentype enumerable value</param>
        /// <param name="SettingName">Name of the Setting</param>
        /// <param name="SettingValue">Value</param>
        /// <returns></returns>
        public async Task SetData(SecurityService Security, string PageName, string ControlName, Screentypes ScreenType, string SettingName, string SettingValue)
        {
            security = Security;

            if (security.User != null && !string.IsNullOrEmpty(PageName) && !string.IsNullOrEmpty(ControlName) && !string.IsNullOrEmpty(SettingName))
            {
                string s = await GetData(security, PageName, ControlName, ScreenType, SettingName);

                if (!string.IsNullOrEmpty(s))
                {
                    // Update Setting Value inside the collection
                    foreach (var d in Data)
                    {
                        if (d.PageName == PageName && d.ControlName == ControlName && d.ScreenType == Screentypes.Desktop && d.SettingName == SettingName)
                        {
                            d.SettingValue = SettingValue;
                            d.TimeStamp = DateTime.Now;
                        }

                    }
                }
                else
                {
                    // Create new record and add it to collection
                    if (Data == null)
                        Data = new List<ApplicationUserStateValues>();

                    ApplicationUserStateValues v = new ApplicationUserStateValues()
                    {
                        PageName = PageName,
                        ControlName = ControlName,
                        ScreenType = ScreenType,
                        SettingName = SettingName,
                        SettingValue = SettingValue,
                        TimeStamp = DateTime.Now
                    };
                    
                    Data.Add(v);
                }
                // State in der DB speichern
                if (Data.Count() > 0)
                {
                    security.User.ApplicationUserState = JsonSerializer.Serialize<List<ApplicationUserStateValues>>(Data);
                    Task<ApplicationUser> task = security.UpdateUser(security.User.Id, security.User);
                }

            }
        }
    }
}

This class ApplicationUserState is instantiated in page.razor.cs

        public ApplicationUserState state = new ApplicationUserState();

Method SaveStateAsnyc saves session data by using state.SetData()

        /// <summary>
        /// Sichert die State-Daten des DataGrids in den State-Speicher
        /// </summary>
        /// <returns></returns>
        private async Task SaveStateAsync()
        {
            await Task.CompletedTask;

            await state.SetData(Security, "Beleg", "datagridBeleg", ApplicationUserState.Screentypes.Desktop, "DataGridSettings", JsonSerializer.Serialize<DataGridSettings>(Settings));
        }

For dropdowngrid settings are saved by saving variable multipleValues by setting the value

        List<Guid> _multipleValues;
        public List<Guid> multipleValues
        {
            get
            {
                return _multipleValues;
            }
            set
            {
                if (_multipleValues != value)
                {
                    _multipleValues = value;
                    InvokeAsync(SaveStateAsync2);
                }
            }
        }

Method SaveStateAsync2 saves the value of multipleValue like SaveStateAsync

        /// <summary>
        /// Sichert die State-Daten des dropdownDataGrids in den State-Speicher
        /// </summary>
        /// <returns></returns>
        private async Task SaveStateAsync2()
        {
            await Task.CompletedTask;

            await state.SetData(Security, "Beleg", "dropdownDatagridFilter", ApplicationUserState.Screentypes.Desktop, "dropdownDataGridFilterSettings", JsonSerializer.Serialize<List<Guid>>(multipleValues));

        }

During main load method settings are read from db and deserialized

        /// <summary>
        /// Lädt die State-Daten aus dem State-Speicher, deserialisiert sie und speichert sie in der _settings-Variable für das DataGrid
        /// </summary>
        /// <returns></returns>
        private async Task LoadStateAsync()
        {
            await Task.CompletedTask;

            var result = await state.GetData(Security, "Beleg", "datagridBeleg", ApplicationUserState.Screentypes.Desktop, "DataGridSettings");

            if (!string.IsNullOrEmpty(result))
            {
                _settings = JsonSerializer.Deserialize<DataGridSettings>(result);
            }
        }
        /// <summary>
        /// Lädt die State-Daten aus dem State-Speicher, deserialisiert sie und speichert sie in der _settings-Variable für das dropdownDataGrid
        /// </summary>
        /// <returns></returns>
        private async Task LoadStateAsync2()
        {
            await Task.CompletedTask;

            var result = await state.GetData(Security, "Beleg", "dropdownDatagridFilter", ApplicationUserState.Screentypes.Desktop, "dropdownDataGridFilterSettings");
            if (!string.IsNullOrEmpty(result))
            {
                _multipleValues = JsonSerializer.Deserialize<List<Guid>>(result);
            }
        }