Поделиться через


управление состоянием на стороне Blazor сервера ASP.NET

Замечание

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Для получения дополнительной информации см. Политику поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.

В этой статье описываются распространенные подходы к обслуживанию данных пользователя (состояния) в сценариях на стороне Blazor сервера.

Поддержание состояния пользователя

Серверная часть Blazor — это платформа приложений с отслеживанием состояния. В большинстве случаев приложение поддерживает подключение к серверу. Состояние пользователя хранится в памяти сервера в схеме.

Примеры состояния пользователя, хранящегося в контуре, включают:

  • Иерархия экземпляров компонентов и их последних результатов отрисовки в отображенном пользовательском интерфейсе.
  • Значения полей и свойств в экземплярах компонента.
  • Данные, хранящиеся в экземплярах службы внедрения зависимостей (DI), областью действия которых является контур.

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

Если пользователь испытывает временный сбой сетевого подключения, Blazor пытается повторно подключить пользователя к исходному каналу с сохранением исходного состояния. Однако повторное подключение пользователя к исходному каналу в памяти сервера не всегда возможно.

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

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

Сохранение состояния пользователя

Сохраняемость состояния не обеспечивается автоматически. При разработке приложения необходимо предпринять шаги для реализации сохранения состояния данных.

Как правило, состояния поддерживаются между контурами, где пользователи активно создают данные, а не просто считывают уже существующие данные.

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

  • Многошаговые веб-формы: пользователю требуется время на повторный ввод данных, если состояние нескольких завершенных шагов потеряно. В этом сценарии пользователь потеряет состояние, если покинет форму и вернется к ней позже.
  • Корзины покупок: любой коммерчески важный компонент приложения, представляющего потенциальный доход, может быть сохранен. Пользователь, который теряет свое состояние, и, таким образом, их корзину покупок, может приобрести меньше продуктов или услуг, когда они возвращаются на веб-сайт позже.

Приложение может сохранять только состояния приложения. Пользовательские интерфейсы не могут быть сохранены, например экземпляры компонентов и их деревья отрисовки. Компоненты и деревья отрисовки обычно не являются сериализуемыми. Для сохранения состояния пользовательского интерфейса, например развернутых узлов элементов управления деревьевидного представления, приложение должно использовать пользовательский код для моделирования поведения этого интерфейса как сериализуемого состояния приложения.

Сохраняемость состояния канала

Во время отрисовки Blazor Web Appна стороне сервера состояние сеанса (канала) пользователя может сохраняться при потере подключения к серверу в течение длительного периода времени или упреждающего приостановки, если полностраничные обновления не активируются. Это позволяет пользователям возобновлять сеанс без потери несохраненных работ в следующих сценариях:

  • Регулирование вкладок браузера
  • Переключение приложений для мобильных устройств
  • Прерывания сети
  • Упреждающее управление ресурсами (приостановка неактивных каналов)
  • Улучшенная навигация

Ресурсы сервера можно освободить, если состояние канала можно сохранить, а затем возобновить позже:

  • Даже при отключении канал может продолжать работать и использовать ЦП, память и другие ресурсы. Сохраняемое состояние потребляет только фиксированный объем памяти, который контролируется разработчиком.
  • Сохраняемое состояние представляет подмножество памяти, потребляемой приложением, поэтому сервер не требуется для отслеживания компонентов приложения и других серверных объектов.

Состояние сохраняется для двух сценариев:

  • Состояние компонента: состояние компонентов, используемых для отрисовки интерактивного сервера, например список элементов, полученных из базы данных или формы, которую пользователь заполняет.
  • Область применимости служб: состояние, хранимое на стороне сервера, например, состояние текущего пользователя.

Условия:

  • Эта функция эффективна только для рендеринга Interactive Server.
  • Если пользователь обновляет страницу (приложение), сохраняемое состояние теряется.
  • Состояние должно быть сериализуемым в формате JSON. Циклические ссылки или сущности ORM могут неправильно сериализоваться.
  • Используйте @key для уникальности при отрисовке компонентов в цикле, чтобы избежать ключевых конфликтов.
  • Сохранять только необходимое состояние. Хранение чрезмерных данных может повлиять на производительность.
  • Нет автоматической гибернации. Необходимо сначала подключиться, а затем явно настроить сохранение состояния.
  • Нет гарантии восстановления. Если сохранение состояния завершается ошибкой, приложение возвращается к стандартному отключённому режиму.

Сохраняемость состояния включена по умолчанию, когда AddInteractiveServerComponents вызывается на AddRazorComponents в файле Program. MemoryCache — это реализация хранилища по умолчанию для отдельных экземпляров приложений и сохраняет до 1000 сохраненных схем в течение двух часов, время хранения можно настроить.

Используйте следующие параметры, чтобы изменить значения по умолчанию поставщика в памяти:

  • PersistedCircuitInMemoryMaxRetained ({CIRCUIT COUNT} заполнитель): максимальное количество контуров, которые необходимо сохранить. По умолчанию используется 1000 каналов. Например, используйте 2000 для хранения состояния до 2000 каналов.
  • PersistedCircuitInMemoryRetentionPeriod ({RETENTION PERIOD} заполнитель): максимальный период хранения в качестве TimeSpan. Значение по умолчанию — два часа. Например, используйте TimeSpan.FromHours(3) для трехчасового периода хранения.
services.Configure<CircuitOptions>(options =>
{
    options.PersistedCircuitInMemoryMaxRetained = {CIRCUIT COUNT};
    options.PersistedCircuitInMemoryRetentionPeriod = {RETENTION PERIOD};
});

Сохранение состояния компонента в схемах основано на существующем PersistentComponentState API, который продолжает сохранять состояние для предварительно отрисованных компонентов, переходящих в интерактивный режим отрисовки. Дополнительные сведения см. в разделе ASP.NET Сохраняемость предварительно созданного состояния CoreBlazor.

[ПРИМЕЧАНИЕ] Сохранение состояния компонента для предварительной отрисовки работает для любого интерактивного режима отрисовки, но сохранение состояния контура работает только в режиме отрисовки Interactive Server.

Аннотируйте свойства компонента с помощью атрибута[PersistentState], чтобы включить сохраняемость состояния цепи. В следующем примере элементы идентифицируются с помощью атрибута директивы @key, чтобы обеспечить уникальный идентификатор для каждого экземпляра компонента.

@foreach (var item in Items)
{
    <ItemDisplay @key="@($"unique-prefix-{item.Id}")" Item="item" />
}

@code {
    [PersistentState]
    public List<Item> Items { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Items ??= await LoadItemsAsync();
    }
}

Чтобы сохранить состояние для служб с областью видимости, аннотируйте свойства службы атрибутом [PersistentState], добавьте службу в коллекцию сервисов и вызовите метод расширения RegisterPersistentService с этой службой.

public class CustomUserService
{
    [PersistentState]
    public string UserData { get; set; }
}

services.AddScoped<CustomUserService>();

services.AddRazorComponents()
  .AddInteractiveServerComponents()
  .RegisterPersistentService<CustomUserService>(RenderMode.InteractiveAuto);

[ПРИМЕЧАНИЕ] В предыдущем примере сохраняется состояние UserData, когда служба используется в предварительной подготовке компонентов как для интерактивного сервера, так и для интерактивной отрисовки WebAssembly, так как RenderMode.InteractiveAuto указано в RegisterPersistentService. Однако сохраняемость состояния схемы доступна только для режима отрисовки интерактивного сервера.

Чтобы обрабатывать сохраняемость распределенного состояния (и выступать в качестве механизма сохраняемости состояния по умолчанию при настройке), назначьте приложению значение HybridCache (API: HybridCache): который настраивает собственный период сохраняемости (PersistedCircuitDistributedRetentionPeriodпо умолчанию восемь часов). HybridCache используется, так как он предоставляет единый подход к распределенном хранилищу, который не требует отдельных пакетов для каждого поставщика хранилища.

В следующем примере HybridCache реализован с использованием поставщика хранилища Redis:

services.AddHybridCache()
    .AddRedis("{CONNECTION STRING}");

services.AddRazorComponents()
    .AddInteractiveServerComponents();

В предшествующем примере {CONNECTION STRING} заполнитель обозначает строку подключения кэша Redis, которая должна быть предоставлена с использованием безопасного подхода, например, инструмента Secret Manager в Development среде или Azure Key Vault с Azure Managed Identities для приложений, развернутых в Azure в любой среде.

Приостановка и возобновление каналов

Приостановка и возобновление каналов для реализации пользовательских политик, которые повышают масштабируемость приложения.

Приостановка канала хранит сведения о канале в хранилище браузера на стороне клиента и вытесняет канал, который освобождает ресурсы сервера. Возобновление работы канала устанавливает новый канал и инициализирует его с помощью сохраняемого состояния.

Из обработчика событий JavaScript:

  • Вызов приостановки Blazor.pause канала.
  • Вызов Blazor.resume для возобновления канала.

В следующем примере предполагается, что канал не требуется для приложения, которое не отображается:

window.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    Blazor.pause();
  } else if (document.visibilityState === 'visible') {
    Blazor.resume();
  }
});

Сохранение состояния при смене каналов

Как правило, состояния поддерживаются между контурами, где пользователи активно создают данные, а не просто считывают уже существующие данные.

Чтобы сохранять состояние при смене каналов, приложение должно хранить данные не в памяти сервера, а в другом месте. Сохраняемость состояния не обеспечивается автоматически. При разработке приложения необходимо предпринять шаги для реализации сохранения состояния данных.

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

  • Многошаговые веб-формы: пользователю требуется время на повторный ввод данных, если состояние нескольких завершенных шагов потеряно. В этом сценарии пользователь потеряет состояние, если покинет форму и вернется к ней позже.
  • Корзины покупок: любой коммерчески важный компонент приложения, представляющего потенциальный доход, может быть сохранен. Пользователь, который теряет свое состояние, и, следовательно, свою корзину с покупками, может приобрести меньше товаров или услуг, когда вернется на сайт позже.

Приложение может сохранять только состояния приложения. Пользовательские интерфейсы не могут быть сохранены, например экземпляры компонентов и их деревья отрисовки. Компоненты и деревья отрисовки обычно не являются сериализуемыми. Для сохранения состояния пользовательского интерфейса, например развернутых узлов элементов управления деревьевидного представления, приложение должно использовать пользовательский код для моделирования поведения этого интерфейса как сериализуемого состояния приложения.

Хранилище на стороне сервера

Для постоянного хранения данных для нескольких пользователей и устройств приложение может использовать хранилище на стороне сервера. Возможные варианты:

  • Хранилище данных типа BLOB
  • Хранилище значений ключей
  • Реляционная база данных
  • Табличное хранилище данных

После сохранения данных состояние пользователя сохраняется и становится доступным во всех новых каналах.

Дополнительные сведения о вариантах хранения данных в Azure см. здесь:

Хранилище браузера

Дополнительные сведения см. в разделе ASP.NET Управление состоянием Ядра Blazor с помощью защищенного хранилища браузера.

Дополнительные ресурсы