Blazor: Server и WebAssembly одновременно в одном приложении11.03.2021 09:17
ASP.NET Core Blazor — это разработанная Microsoft веб-платформа, предназначенная для запуска на стороне клиента в браузере на основе WebAssembly (Blazor WebAssembly) или на стороне сервера в ASP.NET Core (Blazor Server), но две эти модели нельзя использовать одновременно. Подробнее о моделях размещения написано в документации.
В статье я расскажу о том, как
запустить Server и WebAssembly одновременно в одном приложении,
переключаться с Server на WebAssembly без перезагрузки приложения,
реализовать универсальный механизм аутентификации,
синхронизировать состояние Server и WebAssembly с помощью gRPC.
TL; DR:
Gif с демонстрацией полученного результата
Пример доступен на github.
Введение: зачем это нужно
Обе модели размещения имеют свои преимущества и свои недостатки:
Преимущества Blazor Server:
Небольшой объём загружаемых данных (blazor.server.js без сжатия ~ 250 КБ).
Быстрая загрузка.
Отзывчивый UI.
Недостатки Blazor Server:
Так как изменения DOM рассчитываются на сервере, для отзывчивости UI нужно надёжное и быстрое соединение с сервером.
В случае разрыва соединения, приложение в браузере перестанет работать.
В случае перезапуска сервера, приложение в браузере перестанет работать, а состояние интерфейса будет потеряно.
Сложно масштабировать, так как клиент должен работать только с тем сервером, который хранит его состояние.
Преимущества Blazor WebAssembly
Нет всех недостатков Blazor Server, так как приложение работает в браузере автономно. Например, можно работать offline, или делать PWA.
Недостатки Blazor WebAssembly
Неприлично большой размер: 10 — 15 Мб.
Из-за такого размера от перехода по ссылке до появления интерфейса может пройти 15 — 20 секунд (для первого запуска), что в современном мире уже за гранью допустимого.
Нужно отметить, что пререндеринг доступен для обеих моделей размещения, и здорово улучшает отзывчивость, мы будем его использовать. Но даже со включенным пререндерингом для WebAssembly интерфейс будет оставаться неотзывчивым слишком долго, те же 15 — 20 секунд для первого запуска и 5 — 10 секунд для повторных.
Чтобы объединить преимущества Server и WebAssembly, у меня появилась идея реализовать гибридный режим работы: приложение должно запускаться в режиме Server, а позже переходить в режим WebAssembly незаметно для пользователя, например, во время навигации между страницами.
Далее я расскажу как у меня получилось это реализовать.
Часть 1: запуск Server и WebAssembly одновременно
Начать нужно с размещения WebAssembly приложения в приложении ASP.NET Core и включения Prerendering.
В такой конфигурации запуск Blazor начинается в файле _Host.cshtml с добавления на страницу компонента, который создаст для нас DOM нашего приложения, и загрузки скрипта, делающего наше приложение интерактивным.
Для Server это выглядит так:
А для WebAssembly так:
Поэтому нам ничего не мешает загрузить их одновременно:
Работать это, естественно, не будет. Дело в том, что тег превращается в такой html:
В процессе инициализации приложения, blazor ищет этот фрагмент, а затем заменяет его на DOM приложения. Если скрипты blazor.server.js и blazor.webassembly.js запустить одновременно, они оба будут конкурировать за первый компонент, игнорируя второй.
Этого легко избежать, если начинать запуск blazor.webassembly.js только после того, как blazor.server.js закончил работу, примерно так:
var loadWasmFunction = function () {
// Дождёмся момента, когда blazor.server.js закончит работу
if (srvrApp.innerHTML.indexOf('