Как хранить данные сеанса в серверной среде - PullRequest
0 голосов
/ 24 декабря 2018

В серверном приложении Blazor я хотел бы сохранить состояние, которое сохраняется между переходами по страницам.Как я могу это сделать?

Обычное состояние сеанса ASP.NET Core, по-видимому, недоступно, так как наиболее вероятно следующее примечание в Сеанс и состояние приложения в ASP.NET Core :

Сеанс не поддерживается в приложениях SignalR , поскольку SignalR Hub может выполняться независимо от контекста HTTP.Например, это может произойти, когда длинный запрос опроса остается открытым концентратором после истечения срока действия контекста HTTP запроса.

Проблема GitHub Добавить поддержку SignalR для сеанса упоминает, что вы можете использовать Context.Items .Но я не знаю, как его использовать, то есть не знаю, как получить доступ к экземпляру HubConnectionContext.

Какие у меня есть варианты для состояния сеанса?

Ответы [ 2 ]

0 голосов
/ 01 августа 2019

Стив Сандерсон подробно рассказывает о том, как сохранить состояние.

Для сервера на стороне сервера вам потребуется использовать любую реализацию хранилища в JavaScript, которая может быть файлами cookie, параметрами запроса илиНапример, вы можете использовать локальное / сессионное хранилище .

. В настоящее время пакеты NuGet реализуют это через IJSRuntime, например BlazorStorage или Microsoft.AspNetCore.ProtectedBrowserStorage

Сейчасхитрость заключается в том, что серверный блейзор выполняет предварительный рендеринг страниц, поэтому код представления Razor будет выполняться и выполняться на сервере еще до его отображения в браузере клиента.Это вызывает проблему, когда IJSRuntime и, следовательно, localStorage недоступны в настоящее время. Вам нужно будет либо отключить предварительный рендеринг, либо дождаться отправки страницы, сгенерированной сервером, в браузер клиента и установить соединение обратно с сервером

Во время предварительного рендеринга нетинтерактивное соединение с браузером пользователя, и у браузера еще нет страниц, на которых он может запускать JavaScript.Поэтому невозможно взаимодействовать с localStorage или sessionStorage в то время.Если вы попытаетесь, вы получите ошибку, похожую на то, что вызовы взаимодействия JavaScript не могут быть выполнены в это время.Это связано с тем, что компонент выполняется предварительная визуализация.

Чтобы отключить предварительную визуализацию:

(...) откройте файл _Host.razor и удалите вызов Html.RenderComponentAsync.Затем откройте файл Startup.cs и замените вызов endpoints.MapBlazorHub() на endpoints.MapBlazorHub<App>("app"), где App - это тип вашего корневого компонента, а «app» - селектор CSS, указывающий, где в документе должен находиться корневой компонент.быть помещенным.

Когда вы хотите продолжить предварительную визуализацию:

@inject YourJSStorageProvider storageProvider

    bool isWaitingForConnection;

    protected override async Task OnInitAsync()
    {
        if (ComponentContext.IsConnected)
        {
            // Looks like we're not prerendering, so we can immediately load
            // the data from browser storage
            string mySessionValue = storageProvider.GetKey("x-my-session-key");
        }
        else
        {
            // We are prerendering, so have to defer the load operation until later
            isWaitingForConnection = true;
        }
    }

    protected override async Task OnAfterRenderAsync()
    {
        // By this stage we know the client has connected back to the server, and
        // browser services are available. So if we didn't load the data earlier,
        // we should do so now, then trigger a new render.
        if (isWaitingForConnection)
        {
            isWaitingForConnection = false;
            //load session data now
            string mySessionValue = storageProvider.GetKey("x-my-session-key");
            StateHasChanged();
        }
    }

Теперь к фактическому ответу, где вы хотите сохранить состояние между страницами, вы должны использовать CascadingParameter.Крис Сэйнти объясняет это как

Каскадные значения и параметры - это способ передачи значения от компонента всем его потомкам без использования традиционных параметров компонента.

Это будет параметр, который будет классом, который содержит все ваши данные о состоянии и предоставляет методы, которые можно загружать / сохранять через поставщика хранилища по вашему выбору.Это объясняется в блоге Криса Сэйнти , в заметке Стива Сандерсона или в документах Microsoft

Обновление: Microsoft опубликовала новые документы, объясняющие Blazor'sуправление состоянием

Обновление 2: обратите внимание, что в настоящее время BlazorStorage работает неправильно для серверной версии Blazor с последним предварительным просмотром .NET SDK.Вы можете следить за этой проблемой , где я разместил временное решение

0 голосов
/ 27 декабря 2018

Подход бедняка к государству подсказывает @JohnB: воспользуйтесь услугой scoped .В серверной части Blazor область обслуживания привязана к соединению SignalR.Это самая близкая вещь к сессии, которую вы можете получить.Это, безусловно, личное для одного пользователя.Но это также легко теряется.Перезагрузка страницы или изменение URL-адреса в списке адресов браузера загружает, запускает новое соединение SignalR, создает новый экземпляр службы и таким образом теряет состояние.

Итак, сначала создайте службу состояния:

public class SessionState
{
    public string SomeProperty { get; set; }
    public int AnotherProperty { get; set; }
}

Затем настройте службу в классе Startup проекта App (не проект сервера):

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<SessionState>();
    }

    public void Configure(IBlazorApplicationBuilder app)
    {
        app.AddComponent<Main>("app");
    }
}

Теперь вы можете внедрить состояние в любой Blazorстраница:

@inject SessionState state

 <p>@state.SomeProperty</p>
 <p>@state.AnotherProperty</p>

Лучшие решения по-прежнему приветствуются.

...