В чём разница между Blazor Server и Blazor WebAssembly?
Blazor Server выполняет компоненты на сервере и синхронизирует UI через SignalR; Blazor WebAssembly загружает .NET runtime в браузер и работает полностью на клиенте без постоянного серверного соединения.
Blazor Server vs Blazor WebAssembly
Оба варианта позволяют писать интерактивные веб-интерфейсы на C#, но архитектурно различаются принципиально: где исполняется .NET код и как передаются UI-обновления.
Blazor Server
Компоненты исполняются на сервере ASP.NET Core. Браузер подключается по SignalR (WebSocket с fallback на long polling). Каждое событие (клик, ввод) отправляется на сервер, сервер вычисляет diff виртуального DOM и возвращает патч клиенту. Состояние хранится в памяти сервера.
// Program.cs — Blazor Server
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
Характеристики:
- Быстрый первый рендеринг — браузер получает готовый HTML.
- Прямой доступ к серверным ресурсам: EF Core, файловая система, внутренние API.
- Требует постоянного SignalR-соединения; обрыв = потеря состояния.
- Состояние в памяти: 50–250 КБ на пользователя. 10 000 соединений = ~2 ГБ RAM.
- Задержка UI зависит от latency до сервера (критично при >100 мс RTT).
Blazor WebAssembly
При первом запросе браузер загружает .NET WebAssembly runtime (~8 МБ gzip) и DLL приложения, после чего весь код исполняется локально. Серверное соединение используется только для вызовов API.
// Program.cs — Blazor WebAssembly
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
Характеристики:
- После загрузки — низкая latency UI, нет SignalR overhead.
- Подходит для PWA (работа офлайн).
- Медленная первая загрузка: 5–15 секунд без prerender.
- Нет прямого доступа к серверу — только через HTTP API.
- Ограниченная безопасность: код в браузере виден пользователю.
Сравнение по ключевым параметрам
- Место исполнения: Server — на сервере; WASM — в браузере.
- Загрузка: Server — мгновенная; WASM — 5–15 с при первом запуске.
- Масштабирование: Server — требует sticky sessions или backplane; WASM — статические файлы, CDN.
- Доступ к БД: Server — прямой через DI; WASM — только через REST/gRPC.
- Офлайн: Server — нет; WASM — возможен с PWA.
- SignalR: Server — обязателен; WASM — опционален.
Пример: одинаковый компонент в обоих вариантах
@page "/weather"
@inject IWeatherService WeatherSvc
@if (_forecast is null)
{
<p>Loading...</p>
}
else
{
<p>Temp: @_forecast.TempC °C</p>
}
@code {
private WeatherForecast? _forecast;
protected override async Task OnInitializedAsync()
{
// В Server: IWeatherService может обращаться к БД напрямую
// В WASM: IWeatherService вызывает HttpClient
_forecast = await WeatherSvc.GetCurrentAsync();
}
}
Подводные камни
- В Blazor Server потеря SignalR-соединения (перезагрузка прокси, NAT timeout) приводит к потере всего состояния компонентов — пользователь видит «Reconnecting...» и при неудаче — перезагрузку страницы.
- В WASM секреты (строки подключения, API-ключи) нельзя хранить в коде — они видны в DevTools Network; используйте BFF или серверный прокси.
- В Blazor Server потребление памяти растёт линейно с числом соединений; необходим мониторинг и circuit breaker при OOM.
- WASM не поддерживает многопоточность в полной мере —
ThreadиMutexограничены (работает только один WebAssembly thread без SharedArrayBuffer). - Blazor Server в docker-контейнере за nginx требует настройки
proxy_read_timeoutиproxy_send_timeoutдля поддержания долгоживущих WebSocket-соединений. - При гибридном подходе (Blazor Web App) один и тот же компонент может переключаться между режимами — убедитесь, что зависимости доступны в обоих контекстах.
Common mistakes
- Путать Blazor Server и WebAssembly как разные runtime-модели с похожим механизмом из другой версии или платформы.
- Игнорировать runtime-границы Blazor: lifecycle, DI scope, SQL translation, UI thread или platform API.
- Не обсуждать null/empty/error cases и поведение под нагрузкой.
What the interviewer is testing
- Кандидат объясняет Blazor Server и WebAssembly как разные runtime-модели на конкретном примере, а не только определением.
- Указывает последствия для производительности, тестируемости и поддержки.
- Различает документированное поведение текущего стека и устаревшие практики.