Blazor — обзор возможностей

Привет. Сегодня хочу рассказать о новой экспериментальной технологии — Blazor. Данная технология позволяет запускать C# код в WebAssembly, что позволяет использовать .NET в браузере вместе или вместо JavaScript. Что это даёт и какие возможности есть на данный момент хочу показать в данной статье.

Для начала работы, на момент написания статьи, необходимо:

Visual Studio 2017 (15.7) — вы можете установить preview версию параллельно основной. Visual Studio должна содержать ASP.NET and web development.
.NET Core 2.1 Preview 1 SDK
Расширение ASP.NET Core Blazor Language Services которое добавит шаблон Blazor приложения в список доступных ASP.NET Core Web шаблонов
Выбор шаблона Blazor при создании нового ASP.NET Core проекта

Проект представляет из себя следующее:

Начальная структура Blazor проекта

BlazorApp.Shared — здесь только 1 класс WeatherForecast, представляющий из себя модель для работы с данными о погоде.
BlazorApp.Server — это ASP.NET MVC приложение, не чем не выделяющиеся. Здесь стоит обратить внимание на содержимое Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

    services.AddResponseCompression(options =>
    {
        options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
        {
            MediaTypeNames.Application.Octet,
            WasmMediaTypeNames.Application.Wasm,
        });
    });
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseResponseCompression();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMvc(routes =>
    {
        routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");
    });

    app.UseBlazor<Client.Program>();
}

Здесь интересна строка app.UseBlazor<Client.Program>(); здесь добавляется Blazor с классом Client.Program
BlazorApp.Client — здесь, непосредственно, и ведётся работа с компонентами Brazor.
Класс Program содержит следующее:

public class Program
{
    static void Main(string[] args)
    {
        var serviceProvider = new BrowserServiceProvider(configure =>
        {
            // Add any custom services here
        });

        new BrowserRenderer(serviceProvider).AddComponent<App>("app");
    }
}

После запуска, код страницы будет содержать следующее:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BlazorApp</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>Loading...</app>

    <script src="css/bootstrap/bootstrap-native.min.js"></script>
    <script src="_framework/blazor.js" main="BlazorApp.Client.dll" entrypoint="BlazorApp.Client.Program::Main" references="BlazorApp.Shared.dll,Microsoft.AspNetCore.Blazor.Browser.dll,Microsoft.AspNetCore.Blazor.dll,Microsoft.Extensions.DependencyInjection.Abstractions.dll,Microsoft.Extensions.DependencyInjection.dll,mscorlib.dll,netstandard.dll,System.Core.dll,System.Diagnostics.StackTrace.dll,System.dll,System.Globalization.Extensions.dll,System.Net.Http.dll,System.Runtime.Serialization.Primitives.dll,System.Security.Cryptography.Algorithms.dll" linker-enabled="true"></script></body>
</html>

Какие библиотеки подгружаются и их размеры можно увидеть здесь:

Размеры подгружаемых библиотек в Blazor проекте

Как можно увидеть, подгружается несколько лишних мегабайт. Конечно, для современных скоростей интернета это не проблема, к тому же, если говорить про JavaScript фреймворки, то, например, Angular будет ненамного меньше весить. Так что это не должно стать проблемой.

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

Внешний вид проекта, созданного по шаблону Blazor

Собственно, ничего особенного и интересного, есть 3 страницы, одна с приветствием, на второй показан пример обработки события щелчка мыши, а на третей пример загрузки JSON данных, но давайте посмотрим, как это всё работает.

Откроем Pages\Counter.cshtml. Она небольшая, по этому приведу здесь весь код:

@page "/counter"
<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button @onclick(IncrementCount)>Click me</button>

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

@page — данная директива показывает, что данный файл является страницей и на неё можно маршрутизировать запросы. "/counter" это и есть корректный маршрут для данной страницы
@currentCount — выводит значение переменной. Если проводить аналогию с Angular, то здесь было бы написано {{currentCount}}
@onclick(IncrementCount) — при щелчке на данный объект вызывается функция IncrementCount. В IncrementCount происходит увеличение значения на 1.

Здесь можно увидеть связку переменных с HTML элементами, при этом, данная связь однонаправленная, при изменении переменной currentCount в коде, она изменеяется и в HTML. Если же нужна двунаправленная связь, то можно воспользоваться директивой @bind, также можно добавлять событие на изменение значения, используя @onchange

Использование DLL библиотек

Одна их тех вещей, которая делает Blazor перспективным, это использование обычных DLL файлов в проектах. Вы можете подгрузить необходимую библиотеку из Nuget или добавить её в проект вручную и начать использовать.

Например, есть библиотека mXparser, которая представляет из себя парсер математических выражений. Сама библиотека весит немногим более 600KB, со своими задачами справляется успешно. Если есть необходимость в браузере на стороне пользователя добавить возможность вычислять записанные выражения, то достаточно подключить эту библиотеку, добавить событие на изменение записанных данных и поставленная задача будет реализована.

Код, который был добавлен (на странице так же добавлен @using org.mariuszgromada.math.mxparser;):

<input type="text" style="width:35%;" @onchange(value => MathIt(value)) /> = <b>@result</b>

@functions {
    string result = "";
    void MathIt(object text)
    {
        Console.WriteLine(text);
        var str = (string)text;
        if (!string.IsNullOrEmpty(str))
        {
            var x = new Expression(str);
            result = x.calculate().ToString();
        }
    }
}

Теперь можно вводить математические выражения, и они будут вычислены. Вот как это будет работать:

Вычисления математических выражений используя mXparser используя Blazor, непосредственно в браузере

Это открывает огромные возможности, так как готовых библиотек очень много. Кроме того, на мой взгляд, делать реализацию различных алгоритмов удобнее на C#, нежели JS. Как минимум, наличие строгой типизации помогает избегать множества ошибок, а такие вещи как TypeScript рассматривать здесь я не буду.

Связывание данных

Обычно, когда начинаешь знакомиться с JS фреймворками, в документации получаешь множество примером связывания данных (binding). В Blazor данный механизм уже сейчас работает вполне неплохо. Здесь можно увидеть пример использования:

Привязка данных и вызов JavaScript кода в Blazor

Исходный код писать не буду, его можно увидеть здесь.
А вот так будет работать To Do список, реализованный на Blazor.

To Do список, реализованный в Blazor используя C#, работающий непосредственно в браузере

Исходный код можно увидеть здесь.
Всё это реализовано без использования JavaScript кода, используя C# и возможности Blazor.

Вызов JavaScript кода из Blazor

Если бы совместимость с JS убрали, это была бы проблема, так как сейчас уже существует множество скриптов и библиотек, которые успешно выполняют свои задачи. А сразу отказаться от использования JavaScript полностью, по крайней мере, на реальных проектах не получится.

Для того, чтобы вызвать JS код, необходимо сперва зарегистрировать функцию (JavaScript код):

<script>
    Blazor.registerFunction('ShowMessage', message => {
        if (message == undefined || message == "") { 
            alert("Введите сообщение");
            return;
        }
        alert(message);
    });
</script>

После этого её можно будет вызывать в Blazor из C#:

RegisteredFunction.Invoke<string>("ShowMessage", message);

Логирование в браузере

При использовании JavaScript, если необходимо вывести в консоль какие-то значения для анализа, можно воспользоваться функцией console.log. При использовании Blazor, можно использовать привычные Console.WriteLine. И выведенные данные будут выглядеть следующим образом (сейчас пишется, что данные выведени из WASM):

To Do список, реализованный в Blazor используя C#, работающий непосредственно в браузере

Итоги:

WebAssembly это та технология, которая сможет заменить JavaScript в браузерах в будущем. WebAssembly более совершенна. Пакеты получаются меньше по размеру, работают быстрее. Код, который выполняется скрыт от пользователя, по крайней мере он не может с легкостью открыть исходный код скрипта и проследить логику его выполнения или даже скопировать его с той просторой, как это происходит при использовании JavaScript.

А Blazor, как по мне, отличный эксперимент, который, возможно, вырастет в полноценный продукт, который возьмут на вооружения .NET разработчики. Технология, конечно, еще очень сыра. При работе заметны проблемы, так же не хватает возможности вызывать API браузера напрямую из .NET. Так же, на текущий момент, нельзя производить отладку создаваемых проектов. Но лично мне, понравилось использовать Blazor, C# удобный язык, даже для использовании в браузере. А возможность использование обычных DLL сборок в подобных проектах приводит в восторг.

Надеюсь, что данный проект не забросят и доведут до версии, которую можно будет использовать на реальных проектах.

Для тех, кто дочитал до сюда, настоятельно рекомендую самостоятельно попробовать Blazor в действии, это, как минимум, интересно.
Исходный код показанного тестового проекта: https://github.com/flash2048/BlazorDemo
Здесь можно испробовать показанный пример в действии: http://blazordemoapp.azurewebsites.net/

Приятного программирования.

Добавить комментарий