BlazingPizza: приложение на Blazor от начала и до конца. Часть 1. Настройка среды

Всем привет! Если вы слышали о Blazor, но до сих пор не понимаете, что это такое. То вы по адресу. Это первая статья из цикла 12 статей, которая проведет вас через все круги ада весь процесс создания приложения на Blazor. В конце у нас будет готовый сайт небольшой пиццерии, вполне на уровне готовый сайтов некоторых пиццерий. Поэтому вам будет чем гордится;)
Это будет немного не типичный HelloWorld. Я осознанно пошел на некоторые усложнения которые лучше сразу принять за правила, в частности это типичная трехслойная архитектура: View-Domain-DataAccess.

Я считаю что лучше следовать ей сразу, чем показывать что-то искуственное, не имеющее отношения к жизни. Как показывает практика, многие разработчики, застревают на уровне HelloWorld и потом используют увиденное при проектировании априори крупных приложений (привет моему ex-СамыйЗеленыйБанкСтраны и его Service.cs со всем кодом приложения в одном файле, не шучу).

Я расскажу как мапить данные между слоями без боли и без необходимости писать много строчек кода. Также мы задеплоим всё это дело в Azure DevOps. Да, сейчас это необходимая часть любого процесса разработки, мы все сегодня летаем в облаках, кто-то в on-premises, кто-то в Azure или AWS.

Также чтобы первая статья не была банальным рассказом, о том как нажать одну кнопку в Visual Studio, , а потом другую, подумал будет неплохо устроить небольшой челлендж и впервые попробовать сделать что-то на Linux.

Я рассчитываю, что вы обладаете минимальным знанием Asp.net, C#. Хотя это HelloWorld, я не буду рассказывать, что такое Program.cs.

Далее обсудим, что еще понадобится для программирования под Linux.
Attention: В следующих паре абзацев выражено моё впечатление, полученное от реальной работы с Linux, установившего её из самых благих побуждений, если Linux вызывает у вас восторженные чувства и вы не можете прожить ни дня не открыв командную строку, ты вы можете испортить себе настроение, продолжив чтение этой статьи!

Дистрибутив: Ubuntu


Комфортного программирования по правде говоря, под Linux у вас не получится, но все же если вы хотите сосредоточиться на деле, поставьте Ubuntu 19.10. У меня получилось поставить её со второго раза, хорошо что хоть со второго. И все команды выполнились с первого раза, почти все. Крайне не советую ставить какие-то другие дистрибутивы, я потратил целый день на настройку последней OpenSuse, а потом просто снес её.

Зачем вообще может понадобится разрабатывать под Linux? Ну хотя бы потому-что  .Net Core, его поддерживает и возможно ваш работодатель решит сэкономить и запускать на проде все в Linux. А писать на мой взгляд лучше под той ОС, на которой собственно и будет выполняться ваше приложение.

IDE победитель: Rider


Как я уже сказал, комфортно под Linux писать все равно не получится, по из всех зол, выберем меньшее, Rider.

Помимо неё также есть ещё две популярные то-ли IDE то-ли текстовые редакторы MonoDevelop и Visual Studio Code. Расскажу, о недостатках каждого решения подробнее.

MonoDevelop


Cамая симпатичная из трех редакторов. Читабельные шрифты (низкокачественные шрифты это первое, что вам бросится в глаза при переезде на Linux). Но к сожалению за красивой оболочкой пустота, несмотря на установленные .Net Core 2.1 и 3.1, MonoDevelop мне упорно создавала ConsoleApplication с таргет .Net Core 1.1. Blazor проект не получилось ни создать, ни запустить уже созданный вручную.

Visual Studio Code


Строго говоря это не IDE, это текстовый редактор с подсветкой синтаксиса и возможностью билда. Из плюсов с 3 или 4ой попытки, VS Code чудесным образом запустил созданный мною проект WebAssembly, когда MonoDevelop и Rider отказались это делать. Это плюс. Перечисляю дальше минусы: нечитаемый и мелкий по-умолчанию шрифт, думаю через несколько месяцев регулярной работы, ваши глаза просто сойдут с ума.

Следующий минус вытекает из того что это текстовый редактор, такое простое действие как переименование, перемещение проектов? Все что Visual Studio делает автоматически и мы воспринимаем как должное, здесь делается вручную.

Rider


Здесь все гораздо лучше, чем у товарищей выше, Rider даже подхватил установленный мною template для Blazor WebAssembly. И даже создал приложение, вот только запускать его эта IDE почему-то отказалась. Надо сказать ради справедливости, что Blazor Server, собрался и запустился без проблем.

Также Rider позволяет добавить при создании проекта git репозиторий. Но при этом .gitignore почему-то оказался пустым.

То есть опять же, требуется ручное вмешательство, а Rider на всякий случай напомню, конкурирует с VS и JetBrains берет деньги за свой продукт. Ну и как обычно проблема, вообще на линуксе в принципе, это плохие шрифты, они какие-то очень тонкие, плохо читаемые. Элементы также все мелкие, в них нужно еще прицелиться. Также несколько раз, за два дня работы, Rider повесил систему при загрузке простенького solution. Компьютер пришлось перезагружать reset-ом, что конечно не есть good (update: к моменту окончания написания статьи это произошло уже раз пять).

Победитель в номинации Лучшая C# IDE под Linux:
Rider — несмотря на все недостатки, мне удалось добиться, что эта IDE стабильно собирала и запускала проект (опять же браузер почему-то не запускался по умолчанию), это нужно делать вручную.

Ниже на скриншоте, Rider (обратите внимание на шрифты), и попытка запустить Blazor WebAssembly проект, созданный им же самим Blazor, с MonoDevelop аналогичная ситуация.

a4abiah4ltt2bsqbsrfomjxyv6q.png

Если все так плохо, зачем пользоваться Linux?


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

К тому же несовершенство инструментов разработки под Linux подталкивает нас к большому количеству ручных действий, которые позволят немного больше узнать о том как работает .Net под капотом и понять как много работы за нас выполняет та же Visual Studio.

Что мы хотим получить?


В конце мы получим симпатичное приложение, как на примере ниже:

pttpq8joyyabngjyclb6lrzhet4.png

А теперь за дело. Начнем с установки .Net Core 3.1

Установка .Net Core 3.1


.Net Core 3.1.1 SDK последняя доступная на данный момент версия SDK, она доступна в репозитории Ubuntu. Blazor очень быстро меняется поэтому для работы с Blazor WebAssembly использовать именно 3.1.1, последнюю из стабильных версий.

В начале нам нужно зарегистрировать ключ Майкрософт и их репозиторий, делается это следующими командами в приложении Terminal(нажимаем кнопку Win и вводим Term, оно должно появиться в списке доступных):

3byu9g5hx7xgbpndx0ngqtsjg-q.png

  1. wget -q https://packages.microsoft.com/config/ubuntu/19.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  2. sudo dpkg -i packages-microsoft-prod.deb


Теперь переходим непосредственно к установке .Net Core SDK:

  1. sudo apt-get update
  2. sudo apt-get install apt-transport-https
  3. sudo apt-get update
  4. sudo apt-get install dotnet-sdk-3.1


Установка Blazor WebAssembly template


С установкой .Net Core закончили, теперь нужно установить Blazor WebAssembly Template, который напомню пока находится в стадии Preview из которой он выйдет сразу в релиз в мае. Буквально за день до того как я начал писать статью, 28ого января вышла обновленная версия 3.2.0-preview1.20073.1(h)

  1. dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.2.0-preview1.20073.1

    После создания сбилдим проект и наконец запустим, чтобы насладиться, каким никаким результатом (первая команда выполняется на уровне файла BlazingPizza.sln):

  2. dotnet build

    Всё должно было пройти без проблем, перейдем в папку Server и выполним:

  3. dotnet run


И видим результат:

msdqdkuiqhtryxnush-q4yocnb8.png

Установка Git


Если у вас все ещё не был установлен Git, то самое время сделать это. Строго говоря первую команду делать совсем не обязательно, Ubuntu попросит вас ввести пароль, если для выполнения команды требуется повышение привилегий, мы предвосхитим его=):

  1. sudo su
  2. add-apt-repository ppa:git-core/ppa
  3. apt update; apt install git


Это еще не все, при исполнении в браузере Blazor использует Mono, а значит нам нужно установить ещё и его.

Установка Mono


Первым делом добавим репозитории Mono в систему:

  1. sudo apt install gnupg ca-certificates
  2. sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
  3. echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
  4. sudo apt update


Теперь установим непосредственно сам Mono:

sudo apt install mono-complete


Это небыстрый процесс который занял минут 10, на моем ноутбуке с процессором Core-i5 6200U, потому что компиляция исходников происходит прямо на вашем компьютере.

Поздравляю! Мы установили всё что нужно для разработки Blazor WebAssembly проектов.
Теперь можно перейти собственно к самому проекту.

Но перед этим немного отдохнём от ввода команд и освежим в памяти, что же такое Blazor WebAssembly.

Blazor WebAssembly и с чем его едят


Blazor это web framework спроектированный для запуска либо на стороне клиента в браузере через технологию WebAssembly (с использованием .Net runtime, а точнее Mono реализации, которая в последнее время благодаря открытию исходников .Net почти не отличается от оригинальной платформы), либо на стороне сервера с хостингом в Asp.Net Core приложении и обменивающейся данными посредством технологии SignalR (с помощью создания Circuits соединений).

Как вы поняли из описания выше Blazor!= .Net WebAssembly implementation.
Если выкинуть из этой связки WebAssembly, вы можете разрабатывать Blazor Server приложение и оно будет работать даже в IE 11, который никогда ничего не слышал о современных технологиях и слава богу больше не услышит.

Так как мы делаем приложение на основе подхода Blazor WebAssembly. То его мы рассмотрим чуть подробнее.

  1. В начале загружается статическая страница index.html В ней есть нестандартный тэг app, который является плейсхолдером для будущего приложения. А так же скрипт blazor.webassembly.js который инициирует заuрузку всех сборок и инициализацию приложения. Скачиваются сборки самого Blazor приложения, его зависимости (например AutoMapper, AutoFac) и Mono рантайм.

    Разработчики из команды Blazor постоянно работают над тем чтобы оптимизировать процесс скачиванию сборок, тем самым сокращая время которое проходит между вводом адреса и открытием страницы.

    Ещё в предыдущей версии Blazor(3.1.0-preview4.19579.2, вышедшей два месяца назад) линкер вычищал неиспользуемый код только из библиотек .Net, сейчас также вычищается код библиотек Blazor, что ещё незначительно сократило время загрузки приложения на компьютер пользователя.

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

  2. Пожалуй, главным минусом этого подхода является сложная отладка, вы не можете расставлять точки останова, вы в них просто не попадете, хотя думаю это временно, ведь можно же было раньше в студии подключаться к IE и дебажить JS код.

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

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


Здесь давно не было картинок, поэтому вот вам одна ниже:)

mvswiyaubh7h73bblpgwbepecto.png

Утилита dotnet


Дальше мы будем активно использовать утилиту из комплекта .Net Core SDK — dotnet.

Она позволяет делать много полезных вещей, нас интересуют лишь несколько:

dotnet build 


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

dotnet new blazorwasm -ho -o BlazingPizza


Позволяет создать новый проект на основе template который идет после слова new, в нашем случае это blazorwasm, здесь например можно было бы указать classlib или console.

Далее идут специфические параметры шаблона, в данном случае это -ho, этот параметр говорит о том что наше приложение будет хоститься на стороне сервера в ASP.NET Core приложении, также .Net создаст для нас Контроллеры, которые мы в частности можем потом использовать для создания web api и обращаться к нему не только из Blazor приложения, но и из других клиентов.

Последний параметр -o указывает папку в которую будет помещено созданное решение, по умолчанию, это текущий каталог.

dotnet run 


Еще одна команда, которая нам пригодится, как следует из названия запускает наше приложение.

Создание проекта


И так выполним знакомую команду для генерации нашего солюшена. Выберите для этого хорошо знакомое место, например папка RiderProjects, которую создал Rider IDE и которая размещается по пути /home/{userName}:

dotnet new blazorwasm -ho -o BlazingPizza


Результатом выполнения будет вот такая структура папок:

5palzyowa6et3bprbxme4gu6pwu.png

По-моему, не лучшая схема, лучше если папки будут иметь префикс с именем солюшена, так привычнее (именно так делает VisaulStudio при создании новых проектов) и позволят понять что это не какая-то доп. служебная папка. Со временем проект может обрасти множеством папок, которые не содержат в себе C# кода, и если вы зайдете в Explorer, будет тяжело соориентироваться где что, к тому же, могут быть какие-то deploy скрипты заложенные на то что в каждой папке имя которой начинается на имя солюшена, находится проект, это нормально, потому-что это многолетнее поведение Visual Studio и на него можно полагаться.

И так переименуем существующие проекты и папки которые их содержат (пока что мы ничего не знаем об IDE, мы же в Linux, к тому же первый раз она не поможет, так как папки и проекты называются по разному):

Client => BlazingPizza.Client
Server => BlazingPizza.Server
Shared => BlazingPizza.Shared

Соответствующие изменения нужно отобразить в файле солюшена BlazingPizza.sln. Там где указан путь к проекту »[Server]\~» и ниже заменим соответственно на «BlazingPizza.[Server]\~» как на скриншоте ниже:

4n1dqhz6sww2m_yerejl9yap2sy.png

Проделаем аналогичные изменения в файле BlazingPizza.Server.csproj:

wcwsd0jvor3cyygkum1rlhihaaq.png

И наконец BlazingPizza.Client.csproj тоже должен у вас выглядить как на скриншоте ниже:

t2o5bmeocwevinpyynvwudjsq2w.png

С изменениями пока что хватит, у нас накопилось достаточно всего, что будет обидно потерять, поэтому подключим к нашему солюшену систему контроля версий. Для этого наконец-то откроем нашу IDE Rider и солюшен, здесь все так же как и в Visual Studio, можно открыть выбрав файл солюшена.

Как только все загрузится, перейдем в меню VCS => Enable Version Control Integration. И здесь подключим Git. Rider добавит в папку с солюшеном служебные файлы и подсветит красным все файлы, это значит что эти файлы не зафиксированы в системе контроля версий.
Первый раз Rider предложит закомитить все что есть в проекте включая содержимое папок bin и obj, нам это конечно же не нужно, все потому что файл .gitignore который добавлен по дефолту пустой. Перенесем его в корень на один уровень с файлом BlazingPizza.sln и заменим его содержимое содержимым из под ката.

Содержимое файла .gitignore
# Default ignored files
/workspace.xml
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk 
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output 
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder 
.mfractor/

# sqlite
*.db

# Don't ignore server launchSettings.json. We need a specific port number for auth to work.
!**/BlazingPizza.Server/Properties/launchSettings.json


После этого количество не закомиченных файлов должно будет резко уменьшится до 31.

Создадим наш первый коммит на вкладке Repository:

op1qillbrks-dougddi10t2w0f4.png

Вводим в описание комита «initial commit» и включаем в комит все файлы нажав на «Unversioned files» => «Add to VCS»:

ntdkt3zpjihhnwi4szqo7bvxs98.png

С инфраструктурой все более менее готово, немного поговорим о содержимом солюшена.

Содержимое Solution


Прямо сейчас переименуем проект BlazingPizza.Shared в BlazingPizza.DomainModels. Здесь надо сказать что Rider несмотрю на пометку experimental отлично справился. Запустите проект и убедитесь что все функционирует и ничего не поломано

fsqw3nh4oqxlw7anofq0_q7ozbs.png

Здесь неплохо было бы создать комит с изменениями, хотя бы для того что бы просто увидеть как много Rider сделал за нас, напомню если бы это был Visual Studio Code, все это пришлось бы делать ручками самому, посмотрите diff файлов кликнув на них.

myifkm56d5i37nrvprtt_zdmzgo.png

Добавим новые Projects


Добавим ещё несколько проектов, начнем с BlazingPizza.ViewModels. В нём будут отображаться модели отображения на клиенте. Для добавления кликнем на солюшене правой кнопкой и выберем Add => New Project(тип проекта в этом и в последующих в этой части Class Library)

42jjiw_qw5txfi5acdavchdmxga.png


Если что-то пошло не так, или просто не хотите тратить время на настройку и начать сразу со второго урока, исходники здесь.

Ой да, чуть не забыл :) Ссылка на оригинальный проект (MIT License).

© Habrahabr.ru