Сейчас много говорят о WebAssembly и о том, как он проникнет в мир фронтенда. На самом деле еще нет. Есть тонны статей о веб-сборке и о том, как она работает. Я хочу показать вам пример использования кода C# в браузере.

Краткое описание из MDN: WebAssembly — это новый тип кода, который можно запускать в современных веб-браузерах — это низкоуровневый язык, похожий на ассемблер, с компактным двоичным форматом, который работает почти с родной производительностью и поддерживает такие языки, как C. /C++ и Rust с целью компиляции, чтобы их можно было запускать в Интернете. Он также предназначен для работы вместе с JavaScript, что позволяет им работать вместе.

Есть несколько способов, как это сделать. Я хотел бы упомянуть три из них.

  • Первый — использовать Blazor Framework. Он скрывает сложность и дает солидный инструмент для создания SPA-приложений (есть очень хорошая статья про WebAssembly и Blazor).
  • Второй способ — использовать компилятор mono-wasm и скомпилировать код в файл WASM. Он компилирует Ahead of Time и работает очень хорошо (есть статья про MONO и WASM и хорошее объяснение того, как mono компилирует C# в wasm).
  • Третий сценарий — запускать библиотеки .Net в браузере, как это делает платформа Blazor, но без Blazor. Как было сказано в статье выше, есть очень хорошее объяснение того, как работает Blazor. Кроме того, в нем говорится, что для запуска сборок .net нам нужна монокомпилированная версия .NET Runtime, которая была скомпилирована в модуль WASM для выполнения модулей .NET Standard. Это накладные расходы? Конечно, есть некоторые недостатки. Честно говоря, я не знаю. Посмотрим ;).

Другой вопрос: «А нужно ли нам это?». Третий сценарий может быть полезен для тех, кто хочет обновить интерфейсное приложение и поиграть с ним. Тем не менее, я рекомендую использовать скомпилированный AoT файл wasm с приложениями React, Angular или Vue. Blazor framework можно использовать даже в том случае, если проект только начался.

Вот пример того, как использовать этот подход. Есть интерфейсное приложение, основанное на реакции, которое размещено на NodeJs (конечно, о Blazor речь не идет). Пользователи могут загружать любые стандартные модули .Net (сборки библиотек) и извлекать из них метаданные или даже вызывать некоторые методы и использовать результаты для настройки модулей более высокого уровня. Сборки представляют собой небольшие модули с некоторой логикой и определенной ответственностью (пример: расчет прочности материала). Есть некоторые динамические поведения и отражения, поэтому разработчики не могут использовать для этого компиляцию AOT. Передача и извлечение сборок и относительных данных через Http — это большая полезная нагрузка. Сборки не надо где-то сохранять, их нужно распаковать и выполнить, вот и все.

Прежде чем двигаться дальше, я хочу определить задачу: воссоздать пример, упомянутый выше.

Создадим веб-приложение:

dotnet new web -n playDllAndWasm

Затем создайте папку «wwwroot» в файле index.html и измените файл Startup.cs, как показано ниже.

Кроме того, нам нужно добавить предварительно скомпилированную среду выполнения WASM .Net (mono-wasm) и моно-скрипт (mono.js) для его запуска. Вы можете получить их на странице mono-wasm GitHub. Также есть ссылка на Двоичные релизы. Получите упаковщик и с его помощью сгенерируйте целую кучу библиотек для запуска .Net модуля. Я сделал все это, но вот мое предложение: если вы хотите поиграть и не убить себя, вы можете легко клонировать это репозиторий демонстрационных проектов.

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

После этого создадим «управляемую» папку, в которой будут храниться все сборки .Net. Поместите туда первую и самую важную сборку — «mscorlib.dll». Нам это нужно для запуска сборок, потому что это многоязычная стандартная библиотека среды выполнения общих объектов. Идите вперед и добавьте файл index.html в папку «wwwroot» и измените его, как показано ниже.

Что делает код выше? Первый тег сценария создает пустой объект «Модуль» и объявляет только один метод, в котором мы можем выполнять вызовы экземпляра MONO. С помощью экземпляра MONO разработчики могут настраивать и работать с миром .Net. Второй тег script загружает файл mono.js, содержащий команды, которые загружают и запускают mono.wasm. Кроме того, он запускает «onRuntimeInitialized», когда все инициализировано (например, экземпляр MONO) и готово к работе. Запустите и посмотрите, что он делает.

Он показывает только «Hello world!». Однако, если вы откроете консоль разработчика, вы увидите несколько логов из файла mono. Это говорит о том, что среда выполнения готова, что, следовательно, показывает, что мы можем продолжить разработку.

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

dotnet new classlib -n SomeComputing

Будет только один класс с кодом ниже:

Index.html следует изменить. Теперь ему нужны дополнительные библиотеки, чтобы указать, что вызывать, и, конечно же, наша библиотека SomeComputing. Ознакомьтесь с изменениями:

Приведенная выше функция инициализирует привязки .Net WebAssembly и указывает на метод, который следует вызвать. Если он запустится, консоль разработчика покажет вам результат выполнения метода.

Распространенный способ вызова некоторых функций .Net был реализован выше. Это можно было сделать с помощью компиляции AoT mono-wasm и получить только один файл WASM без каких-либо зависимостей сборки .Net. Для продолжения разработки интерфейсу нужны дополнительные библиотеки. Создайте несколько новых проектов netstandard:

dotnet new classlib -n CommonLibrary
dotnet new classlib -n ComputeFibonacci
dotnet new classlib -n ComputeDateTimes

Проект «CommonLibrary» имеет только один файл .cs с интерфейсом.

Интерфейс «IExecutable» — это точка входа сборки. Метод «Выполнить» — это обычное объявление методов, которые будут выполняться на стороне интерфейса. Проекты «ComputeFibonacci» и «ComputeDateTimes» будут зависеть от проекта «CommonLibrary». Затем добавьте в проект SomeComputing новый класс, который будет загружать сборки и запускать их.

WebAssembly не может передавать сложные структуры данных. Кроме того, мы не можем передавать сборки или байты. Сам Javascript записывает байты в выделенный буфер и отправляет указатель на модуль .Net. Модуль .Net, в свою очередь, возьмет на себя чтение этого буфера, преобразование байтов в некоторую структуру (в нашем случае это сборка) и выполнение определенной работы.

Ответ может быть записан в некоторый буфер и получен как указатель. После этого этот буфер может быть прочитан непосредственно в JavaScript. Тем не менее, я ленивый человек, и я думаю, что вы поняли основную идею прохождения и возврата. Вот почему «executeMethod» возвращает строковое значение. Просто и костыльно ;).

ComputeFibonacci и ComputeDateTimes содержат только один класс, реализующий интерфейс «IExecutable».

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

Эта технология довольно молодая. У него много проблем, но он также показывает потенциал. Это быстрый, безопасный, легкий, портативный и открытый стандарт. В этой статье я хотел показать один из кейсов использования этой технологии. Эта статья больше о поощрении. На мой взгляд, мы увидим несколько новых библиотек или даже фреймворков, которые будут основаны на WASM. Есть и хорошие новости о четвертом языке для Интернета. Так что не теряйте времени, прыгайте в поезд :).

Спасибо Ники за потрясающую иллюстрацию.