在 Blazor 中处理会话的最佳方法是什么(不依赖于客户端)?

问题描述 投票:0回答:5

我们使用 Blazor(服务器端)和 .NET 5 来实现新的解决方案,该解决方案需要使用会话来消除完全相同数据的数据库往返。

我们目前正在使用推荐的 ProtectedBrowserStorage 模型,但当我们尝试存储相对较大的数据集时,遇到了浏览器的 25MB 限制。因此,当我们处理需要最终用户查看和操作的数千条记录时,这可能并不理想。我们正在努力为最终用户优化性能。这是一个连接的桌面场景。

是否有更好的方法来处理 Blazor 中的大型会话变量,不受客户端浏览器的限制?

提前致谢。

asp.net .net session blazor blazor-server-side
5个回答
1
投票

消除完全相同数据到数据库的往返。

您可以使用缓存。这允许在会话/用户之间共享数据(可能存在风险,请小心)。它还会减少 I/O。

缓存位于服务器端,您的应用程序也在那里运行。所以一般会比较快。但尚不清楚您的内存限制(每个用户)是什么。


1
投票

您可以使用所有主流浏览器都支持的 IndexedDb。

我在 PWA 中使用此对象存储数据库,但您可以将其与 Blazor 服务器端应用程序或 Blazor WASM 客户端应用程序一起使用。

IndexedDB 的限制对于您以及大多数情况下都不是问题。
浏览器管理数据,您只需决定如何刷新它们的策略。

从这个库开始https://github.com/amuste/DnetIndexedDb并尝试一些示例。


0
投票

根据您的需要,您可以通过几种不同的方法来执行此操作:

级联参数:一个很好的基础知识视频 - https://www.youtube.com/watch?v=ZmDMKp1Q8kA

AppState 方法:一个很好的视频,涵盖了两种不同的方法:https://www.youtube.com/watch?v=BB4lK2kfKf0

这两个问题的主要问题是它们仍在会话中,并且会在刷新或新选项卡时消失。

我所知道的唯一其他解决方案是使用 Redis,这将保留数据,只要您想保留它,但它不会在 blazor 中。 精彩视频:https://www.youtube.com/watch?v=UrQWii_kfIE


0
投票

这取决于您有多少并发用户以及您的系统资源。

单例服务跨会话持续存在,您可以使用任何您想要的数据结构。


0
投票

首先,如果您使用 Blazor Server,则不希望在浏览器存储中使用大型会话 blob。每次访问“会话”(服务器端)时,它都会从客户端浏览器获取对象,将对象传输回服务器,服务器将处理和渲染,将其发送回用户。

无论数据大小如何,我都不会推荐这种方法来管理服务器端频繁访问的状态变量,因为每次访问都会产生返回服务器的延迟。

我发现最适合我的方法是拥有一个自定义状态提供程序组件 - 例如 CustomStatePovider。

不涉及所有细节,但基本上 CustomStateProvider 公开了一个字典,您可以在其中存储所有状态变量(服务器端)。

包含一个 Flush() 方法,允许您有选择地将 KVP 持久保存到您选择的存储类型(ProtectedBrowserStorage、ProtectedLocalStorage、ProtectedSessionStorage - 根据需要实施,示例显示 ProtectedSessionStorage)有关此内容的更多详细信息,请参阅 here

包含一个 Get() 方法,该方法将尝试从字典中加载(如果存在),否则从您选择的持久存储层加载(当然会更新字典)。

注意:您需要使 Get() 异步,但在此示例中尚未这样做

自定义状态提供者:

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedSessionStorage ProtectedSessionStore

@if (_hasLoaded)
{
    <CascadingValue Value="@this">
        @ChildContent
    </CascadingValue>
}
@code {

    [Parameter] 
    public RenderFragment ChildContent { get; set; }

    private bool _hasLoaded;
    public Dictionary<string, object> InMemoryState { get; set; } = new();

    protected override async Task OnInitializedAsync()
    {
        //This will be called if the page refreshes / first load
        //Can load anything you want from your persisted state if required

        _hasLoaded = true;
    }

    public async Task Flush(string key)
    {
        await ProtectedSessionStore.SetAsync(key, InMemoryState);
    }

    public T Get<T>(string key, bool errorOnNotFound = false)
    {
        if (InMemoryState.ContainsKey(key))
        {
            return (T)InMemoryState[key];
        }
        else
        {
            var persistedValue = GetPersistedStateAsync<T>(key, errorOnNotFound).GetAwaiter().GetResult();
            InMemoryState[key] = persistedValue;
            return persistedValue;
        }
    }

    private async Task<T> GetPersistedStateAsync<T>(string key, bool errorOnNotFound = false)
    {
        var val = await ProtectedSessionStore.GetAsync<T>(key);
        if (val.Success)
        {
            return val.Value;
        }
        else
        {
            if (errorOnNotFound)
            {
                throw new Exception($"Storage key not found: {key}");
            }
            else
            {
                //or just default
                return default(T);
            }
        }
    }
}

我通常有两个组件根(一个用于页面,一个用于组件),所有其他组件都继承自它们。在每个中为 CustomStateProvider 实现 CascadingParameter。所有页面和所有组件现在都可以访问自定义状态提供程序。

PageBase(与组件库类似 - 未显示)

@inherits LayoutComponentBase

    @Body

@code {

    [CascadingParameter] 
    public CustomStateProvider CustomStateProvider { get; set; }
}

然后将您的路由器包装在自定义状态提供程序中,您就可以上路了。

 <CustomStateProvider>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <LayoutView Layout="@typeof(LayoutBase)">
                //Add your default 404 message
            </LayoutView>
        </NotFound>
    </Router>
</CustomStateProvider>

@code {

}
© www.soinside.com 2019 - 2024. All rights reserved.