简体   繁体   English

Blazor 服务器存储初始查询参数

[英]Blazor Server Storing Initial QueryParameters

Problem: Storing startup query strings for the life of the session. These startup query strings are optional parameters ("?mode=run") and do not persist between pages.问题:在 session 的生命周期内存储启动查询字符串。这些启动查询字符串是可选参数(“?mode=run”)并且不会在页面之间持续存在。 I'm having a hard time finding a single entry point to set the ProtectedSessionStorage .我很难找到一个入口点来设置ProtectedSessionStorage

1. First I tried a scoped service with dependency injection. 1.首先我尝试了一个带有依赖注入的范围服务。 That works great until the user refreshes the page.在用户刷新页面之前效果很好。

private RunModeSettings _rms = new RunModeSettings();
private readonly ProtectedSessionStorage _protectedSessionStore;
private readonly NavigationManager _navManager;
public RunModeService(ProtectedSessionStorage ProtectedSessionStore, NavigationManager NavManager)
{
    // Constructor is called again if user refreshes the page.
    // If the user is on a page that does not contain the startup query string
    // then the query string is lost / overwritten with null.
    _protectedSessionStore = ProtectedSessionStore;
    _navManager = NavManager;
    _navManager.TryGetQueryString("mode", out string mode);
    // ProtectedSessionStorage is async only
    // Can't check or set session storage
    _rms.RunMode = mode;
         
}

Since ProtectedSessionStorage is alive for the lifetime of the tab I thought I could check the session storage in the service constructor to handle the refresh.由于ProtectedSessionStorage在选项卡的生命周期内有效,我想我可以检查服务构造函数中的 session 存储来处理刷新。 Unfortunately there is no synchronous version to use in the service constructor.不幸的是,服务构造函数中没有可使用的同步版本。

2. Secondly I tried to store the query string parameters by overriding OnInitializedAsync . 2.其次,我尝试通过覆盖OnInitializedAsync来存储查询字符串参数。

// App.razor
protected override async Task OnInitializedAsync()
{
    _navManager.TryGetQueryString("mode", out string mode);
    if ((await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value == null)
        await _protectedSessionStore.SetAsync("RMS", new RunModeSettings() { RunMode = mode});

}

Since we can only use ProtectedSessionStorage in asynchronous overrides it's not guaranteed that OnInitializedAsync in App.Razor component is completed before continuation.由于我们只能在异步覆盖中使用ProtectedSessionStorage ,因此不能保证App.Razor组件中的OnInitializedAsync在继续之前完成。 This introduces a race condition between other early components like <App> , <NavMenu> and <MainLayout> .这在其他早期组件(如<App><NavMenu><MainLayout>之间引入了竞争条件。

In asp.net I could use the Session_Start event as an entry point to store my startup query parameters for the rest of session. Is there a similar entry point in Bazor?在 asp.net 中,我可以使用Session_Start事件作为入口点来存储 session 的 rest 的启动查询参数。Bazor 中是否有类似的入口点?

I came up with something not so elegant but it's simple and works good.我想出了一些不太优雅但很简单而且效果很好的东西。 I register the scoped service as usual.我像往常一样注册范围服务。

builder.Services.AddScoped<RunModeService>();

The scoped services job is to maintain startup query string parameters inside an object named RunModeSettings .作用域服务工作是在名为RunModeSettings的 object 中维护启动查询字符串参数。 Upon construction of the service I use dependency injection to access the query string.在构建服务时,我使用依赖注入来访问查询字符串。 I store the settings object in the session storage incase a refresh happens on a page that does not include the startup query string parameters.我将设置 object 存储在 session 存储中,以防在不包含启动查询字符串参数的页面上发生刷新。

To handle the race condition RunModeSettings are accessed via GetRunModeSettingsAsync .要处理竞争条件,可通过RunModeSettings访问GetRunModeSettingsAsync It returns the object that the service was constructed with or pulls it from the session if ready.它返回构建服务的 object,如果准备就绪,它会从 session 中提取。

public class RunModeService
{
    private RunModeSettings _rms = new RunModeSettings();
    private readonly ProtectedSessionStorage _protectedSessionStore;
    private readonly NavigationManager _navManager;
    public RunModeService(ProtectedSessionStorage ProtectedSessionStore, NavigationManager NavManager)
    {
        _protectedSessionStore = ProtectedSessionStore;
        _navManager = NavManager;
        // Get optional parameters.
        _navManager.TryGetQueryString("mode",out string mode);
        _rms.RunMode = mode;
        // Fire and forget.
        SetRunModeAsync(); 
    }
    public async Task SetRunModeAsync()
    {
        if ((await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value == null)
            await _protectedSessionStore.SetAsync("RMS", _rms);
    }

    public async Task<RunModeSettings> GetRunModeSettingsAsync()
    {
        return (await _protectedSessionStore.GetAsync<RunModeSettings>("RMS")).Value ?? _rms;
    }

}

Now the lifetime of my settings within the service are not determined by the service scope. In my case I use ProtectedSessionStorage to keep the lifetime with the tab.现在我在服务中设置的生命周期不是由服务 scope 决定的。在我的例子中,我使用ProtectedSessionStorage来保持选项卡的生命周期。 Finally, we can access our service as usual.最后,我们可以像往常一样访问我们的服务了。

@inject RunModeService _rms; // Page inject
[Inject] public RunModeService rms { get; set; } // Or code inject

var rms = await _rms.GetRunModeSettingsAsync();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM