Когда в любой момент времени стало понятно, что такое this... Когда неявное преобразование типов осталось только в былинах аксакалов эпохи зарождения веба... Когда умные книжки по Javascript нашли свой бесславный конец в мусорках...     Всё это случилось когда мир фронтенда спас Он.     Ну ладно, сбавим обороты у нашей машины пафоса.     Сегодня я предлагаю вам взглянуть на возможности Blazor в версии .Net 6. Внезапно, под катом не будет очередного ПриветМир, а окажется полноценное SaaS веб-приложение, написанное на Блейзоре, пощупав которое вы сможете гораздо лучше оценить: убийца или чижика съел?     Мы написали приложение-парсер для поиска рекламной аудитории в социальной сети ВКонтакте, где в качестве фронтенда выступает Blazor в клиентском варианте (WebAssembly). Приложение достаточно простое (всего несколько страниц), тем не менее, в нём удалось реализовать следующий функционал: Аутентификация пользователей Совместная работа пользователей (тенанты, права доступа) Валидация в формах ввода Интеграция с внешними Javascript-компонентами Использование браузерных API (локальное хранилище, Page Visibility API)     Работающее приложение можно посмотреть здесь: https://app.venando.ru     Для любителей обмазаться, исходники доступны здесь: https://github.com/a-postx/YA.BlazorVkParser     Приступим к препарированию.     Несмотря на то, что технология WebAssembly (WASM) поддерживается большинством браузеров, скорость её распространения пока достаточно скромная. В случае с Blazor, одним из главных тормозов остаётся скудная система компонентов. Но сегодня (конец 2021-го года) на рынке даже сугубо бесплатных компонентов уже появился какой-никакой выбор.     Мы в своём WASM-клиенте воспользовались одним из самых развитых наборов компонент, который не привязан к конкретному визуальному стеку - Blazorise. С помощью него можно очень просто создавать компоненты уже под свои конкретные нужды и эти компоненты будут изменяться, если вы решите сменить визуал, скажем, с Bootstrap на Material.     Например, мы хотим создать диалоговое окно подтверждения действия, которое будет открываться пользователю в самых разных местах приложения. Для этого с помощью компонентов Блейзорайса создаём сам компонент     И используем его во всех нужных местах, задав привязку к соответствующим колбекам.     Также просто мы ловим события из дочернего компонента в родительском.     Как вы видите по комментарию в коде, в Blazorise ещё довольно много болячек, но с ними уже можно как-то уживаться.     Несмотря на подобного рода болезни роста, ключевым моментом, который побуждает к использованию Blazor как технологии, остаётся то, что на фронте появляется вся мощь .Net.     Обильный послужной список дотнета в бекенде даёт условному фронтендеру широчайший набор средств по решению тех или иных задач в коде, но когда дело доходит до браузеров, HTML и прочих этих ваших компонентов, то тут уже не всё так радужно.      Безусловно, экосистема Блейзора пока не идёт ни в какое сравнение с джаваскриптовой. Хоть сообщество и активно притаскивает из окружающего мира всё новые компоненты, и дотнетчику в дилемме "взять готовый компонент из сообщества" и "написать компонент самому, погрузившись в Javascript" всё меньше приходится прибегать к последнему варианту, но для сколь-либо масштабного приложения без JS не обойтись.     С другой стороны, в папке js нашего SPA-клиента всего пяток файлов, поэтому в итоге можно сказать, что для написания схожего по функционалу приложения Джаваскрипта уже почти не нужно. В кои-то веке кликбейтный заголовок оказался правдой.     В нашем проекте хочется обслуживать только аутентифицированных пользователей. Для реализации достаточно в корневом компоненте (App.razor) обрамить приложение в компонент CascadingAuthenticationState, после чего на любой странице (или в компоненте) вы сможете получить текущее состояние аутентификации с помощью проброса параметра AuthenticationState     Вам остаётся разместить атрибут [Authorize] в файле _Imports.razor соответствующего уровня приложения, чтобы закрыть анонимный доступ ко всем нижележащим страницам. Можно также размещать атрибуты на каждой странице, если у вас будут и страницы для анонимусов.     Сама по себе настройка аутентификации в Blazor очень простая и много где описана. В нашем приложении в качестве поставщика мы выбрали Auth0, поскольку не было желания поддерживать свой сервер токенов и дополнительную логику. Единственный нюанс при использовании Auth0 - необходимость указывать аудиторию вашего бекенд-АПИ в дополнительном параметре AdditionalProviderParameters. Если этого не сделать, то вместо JWT-токена на клиент будет возвращаться токен внутреннего формата Auth0, с помощью которого на ваше серверное приложение аутентифицироваться уже не получится.     Сервисы в серверной части нашего приложения бессостоятельные, но во фронтальной части без контроля состояния не обойтись. Например, нам надо контролировать какой тарифный план у нашего пользователя в текущем тенанте или какую тему он сейчас выбрал для визуальных элементов.     Поскольку наше приложение достаточно простое и не имеет большого количества изменений состояния из разных компонентов, мы воспользовались простым синглтоном, в котором и стали хранить соответствующее состояние, а также модифицировать его.     Компоненты, которые используют модель арендатора, просто подписываются на событие TenantUpdated и выполняют необходимую для себя логику.     Планируете разрабатывать более развесистое приложение? Отлично, тогда вам в помощь будет редукс-подобный контроль состояния - например, проект Fluxor.       Когда нам нужно отделить пользователя от сущностей, которыми он оперирует в приложении, то необходимо добавить слой тенанта. Работа пользователей через абстрактного "арендатора" также даст им возможность шарить сущности между собой, что весьма полезно при создании корпоративных приложений и является частой фишкой продвинутых тарифных планов SaaS-сервисов.     Поскольку аутентификация на бекенде нашего приложения работает через JWT-токены, в клиенте мы добавили шаг по созданию идентификатора арендатора при регистрации нового пользователя: клиент дёргает соответствующий метод сервера, после чего переполучает токен.     На клиенте интересная дилемма возникла при добавлении переключения между тенантами: в Блейзоре существует стандартный механизм переопределения удостоверений пользователя, которым можно воспользоваться, чтобы добавить идентификатор арендатора или любые другие атрибуты.     Однако этот механизм работает только при смене статуса пользователя (напр. с НеАутентифицирован на Аутентифицирован), поэтому для переключения между тенантами пользователю приходится делать дополнительный цикл выхода-входа, что ухудшает пользовательский опыт (в случае OAuth цикл не такой уж быстрый).     Ввиду этой печали для работы с арендаторами было решено отказаться от встроенного механизма удостоверений - идентификатор тенанта просто стал частью состояния приложения, что дало полный контроль над механизмом его переключения. Для этого в корне приложения (App.razor) мы добавили компонент UserAndTenantManager, который и отвечает за подготовку состояния перед тем, как пользователь сможет что-то делать в приложении.     В любом клиентском приложении скорее рано, чем поздно встаёт вопрос интеграции сторонних JS-компонентов и внешних сервисов. В нашем случае потребовалось прикрутить чат и плеер Ютуба.     С плеером всё получилось достаточно просто, благо в мире Джаваскрипт есть VideoJs. Добавляем в наше приложение скрипт плеера, плагина к нему и мааааленький скриптик     Скриптик нужен потому что запуск плеера из Blazor не работает, а вот из JS - работает (не спрашивайте меня почему).     Затем на странице мы просто добавляем элемент плеера и передаём в него необходимые параметры.     Это конечно мало похоже на идеальный код, но что есть то есть.     С чатом повозиться пришлось побольше, но в итоге и он был побеждён. Среди большого количества разработок выбор пал на Чатру. Для добавления чата в наше Blazor-приложение мы традиционно добавляем их скрипт.     Обратите внимание на скрытый виджет при запуске. Мы не хотим, чтобы чат показывался не аутентифицированным пользователям, но при загрузке документа index.html все скрипты оттуда выполняются автоматически, запуская наш чат ещё до того, как запустится WASM. При запуске мы скрываем виджет, а уже после входа пользователя из C# мы дёргаем за ручки управления чатом.     Chatra также позволяет добавлять свои атрибуты в виджет, поэтому мы передаём туда идентификатор арендатора (компонент обновляет его, если пользователь переключился в другой тенант) и его тарифный план, чтобы агент поддержки не запрашивал у пользователя дополнительную информацию.     Таким образом, в Blazor худо-бедно можно использовать сервисы и код с пометкой "только для Javascript", чтобы брать лучшее из двух миров.     Демо-приложение https://app.venando.ru лежит в статическом хранилище Azure, поверх которого подключён CDN от Майкрософта, поэтому загрузка должна быть достаточно быстрой как во Владивостоке, так и в Калининграде. Желающие могут самостоятельно оценить насколько внезапность загрузки клиента на Blazor отличается от стремительности на вашем любимом фреймворке.     Что можно сказать по итогам этого опыта: писать SPA на .Net очень приятно, его возможности дают разработчику отличные инструменты для создания надёжного кода.     Самая большая боль остаётся в долгой перекомпиляции и запуске приложения под дебагом. Хорошая новость в том, что в .Net 6 и VS2022 появилась горячая перезагрузка, которая заметно улучшает эффективность разработчика при дебаге.     Плохая новость в том, что по части производительности всё ещё есть куда стремиться: представленная AOT-компиляция помогает только ценой сильного раздувания размера приложения, что для публичных одностраничников неприемлемо.     Итак: убийца? Пока нет, но технология из разряда "вот поднатореет..."     Пишите в комментариях, насколько плох или хорош Блейзор, поплачем/посмеёмся вместе. Напоминаю: рассмотреть детальки можно в https://github.com/a-postx/YA.BlazorVkParser