Когда C# встречает WebAssembly: новая эра веб-разработки
Представьте себе мир, где вы можете взять свой любимый C#, написать сложный алгоритм обработки изображений, скомпилировать его и запустить прямо в браузере — с производительностью, близкой к нативной. Звучит как научная фантастика? А вот и нет. Это WebAssembly (или просто Wasm) — технология, которая переворачивает представление о том, что можно делать в вебе.
Я сам был скептиком, пока не попробовал. Долгое время казалось, что JavaScript — единственный язык для браузера. Но времена меняются. Сегодня мы, C#-разработчики, можем выйти за пределы серверной части и строить полноценные клиентские приложения на родном языке. В этой статье я покажу вам, как это работает, зачем это нужно и приведу реальные примеры кода.
Что такое WebAssembly простыми словами
Давайте без сложных терминов. WebAssembly — это низкоуровневый бинарный формат инструкций, который выполняется в браузере почти с нативной скоростью. В отличие от JavaScript, который интерпретируется, Wasm компилируется заранее. Это как если бы вы запускали программу на C++ прямо в браузере, но с песочницей безопасности.
Как это связано с C#?
Ваш C#-код может быть скомпилирован в WebAssembly. Вы пишете на привычном языке, используете .NET-библиотеки, а на выходе получаете файл .wasm, который браузер выполняет. Для этого существует несколько подходов, но самый популярный — Blazor WebAssembly.
- Blazor WebAssembly — фреймворк от Microsoft, который запускает .NET в браузере.
- Mono Wasm Runtime — среда выполнения .NET, скомпилированная в Wasm.
- NativeAOT-ot — экспериментальный режим компиляции C# напрямую в Wasm без рантайма.
Зачем вообще использовать C# в браузере?
Хороший вопрос. Ведь есть JavaScript, TypeScript, наконец. Зачем нам C#? Ответ кроется в трёх вещах: производительность, безопасность и экосистема.
1. Производительность для тяжелых вычислений
JavaScript хорош, но для обработки видео, криптографии, симуляций или парсинга больших данных он медленнее. WebAssembly на C# может быть в 10-20 раз быстрее для некоторых задач. Например, если вы пишете редактор изображений на C#, он будет работать в браузере так же быстро, как настольное приложение.
2. Повторное использование кода
У вас есть библиотека на C# для валидации данных на сервере? Просто возьмите и используйте её на клиенте. Никакого дублирования логики на JavaScript. Это снижает количество багов и ускоряет разработку.
3. Безопасность типов
C# — строго типизированный язык. Многие ошибки, которые вылавливаются в рантайме на JavaScript, в C# отлавливаются на этапе компиляции. Для сложных бизнес-приложений это критично.
Практический пример: компиляция C# в WebAssembly
Давайте напишем простую программу на C#, которая вычисляет факториал, и запустим её в браузере. Для этого используем Blazor WebAssembly.
Шаг 1: Создаем проект
dotnet new blazorwasm -o WasmFactorial
cd WasmFactorial
Это создаст стандартный шаблон Blazor WebAssembly. В нём уже есть всё необходимое: рантайм .NET, скомпилированный в Wasm, и мост для взаимодействия с JavaScript.
Шаг 2: Пишем C#-код для вычислений
Добавим сервис для вычисления факториала. Создадим файл Services/FactorialService.cs:
namespace WasmFactorial.Services;
public class FactorialService
{
public long Calculate(int n)
{
if (n < 0) throw new ArgumentException("Число должно быть неотрицательным");
if (n == 0) return 1;
long result = 1;
for (int i = 1; i <= n; i++)
{
result *= i;
}
return result;
}
// Демонстрация сложной логики, которая медленна в JS
public double ComputePi(int iterations)
{
double pi = 0.0;
for (int i = 0; i < iterations; i++)
{
pi += (i % 2 == 0 ? 1.0 : -1.0) / (2 * i + 1);
}
return pi * 4;
}
}
Шаг 3: Используем сервис в компоненте Blazor
Теперь создадим страницу, где пользователь вводит число и получает результат. Откроем Pages/Factorial.razor:
@page "/factorial"
@inject FactorialService FactorialService
<h3>Вычисление факториала на C# в браузере</h3>
<div class="form-group">
<label for="number">Введите число (0-20):</label>
<input type="number" id="number" @bind="inputNumber" min="0" max="20" />
<button class="btn btn-primary" @onclick="CalculateFactorial">
Вычислить
</button>
</div>
@if (result.HasValue)
{
<div class="alert alert-success">
Факториал числа @inputNumber равен: @result
</div>
}
@if (errorMessage != null)
{
<div class="alert alert-danger">
@errorMessage
</div>
}
@code {
private int inputNumber = 5;
private long? result;
private string? errorMessage;
private void CalculateFactorial()
{
try
{
result = FactorialService.Calculate(inputNumber);
errorMessage = null;
}
catch (Exception ex)
{
errorMessage = ex.Message;
result = null;
}
}
}
Запустите проект командой dotnet run и откройте браузер. Вся логика выполняется на стороне клиента, в WebAssembly. Никакого сервера для вычислений не нужно!
Как это работает под капотом
Когда вы запускаете Blazor WebAssembly, происходит следующее:
- Браузер загружает файл
dotnet.wasm— это среда выполнения .NET, скомпилированная в WebAssembly. - Загружаются ваши сборки DLL (скомпилированный C#-код).
- Mono-рантайм исполняет ваш код, используя JIT-компиляцию или интерпретацию (зависит от настроек).
- Взаимодействие с DOM происходит через JavaScript-интероп.
Обратите внимание: загрузка рантайма (~2-3 МБ) — это плата за возможность писать на C#. Но для сложных приложений это окупается производительностью и удобством.
Когда стоит использовать WebAssembly с C#
Не всё так радужно. WebAssembly —