.NET в целом: обзор от Скотта Хансельмана
Скотт Хансельман — ключевой человек для .NET-сообщества: например, на конференции Microsoft Build он ведёт презентацию для разработчиков, а у его микроблога в Twitter около 250 000 подписчиков.
При этом в мире .NET он очень давно. Ещё в 2003-м преподавал C#, то есть был глубоко погружён в тему практически с её появления. А последние 13 лет работает в Microsoft, наблюдая за всем изнутри и общаясь с разработчиками из других компаний.
Поэтому ему хорошо видна общая картина: он лично наблюдал, как эта экосистема развивалась со временем, и знает, как она используется разными разработчиками для разных целей. И этим летом на нашей конференции DotNext он выступил с докладом, посвящённым не каким-то конкретным деталям, а как раз общему обзору .NET — от прошлого до будущего. А мы решили сделать для Хабра текстовую расшифровку, чтобы стало можно не только посмотреть доклад на английском, но и прочитать на русском.
.NET сейчас
Название доклада менялось несколько раз. Вначале он назывался «Прошлое и будущее .NET», потом ».NET 5», потом «Будущее .NET», потом «Куда идёт .NET». На самом деле, формулировка не так уж важна, основная мысль следующая: .NET стал платформой, на которой можно создать всё, что угодно. Приложения для ASP.NET, веб-приложения, приложения для консолей, десктопные приложения, огромные облачные приложения, приложения для iPhone, Android, Apple Watch. Множество игр создано при помощью C# и Unity, и они основаны на .NET. У меня .NET также запущен на Raspberry Pi. Наконец, в последнее время .NET стали также использовать в области ИИ и машинного обучения. Благодаря этому многообразию с .NET сегодня сложилась интересная ситуация.
Предположим, вы устроились на работу программистом ASP.NET, работаете в основном с веб-приложениями и воспринимаете себя как веб-программиста. Если вас кто-то спросит, кем вы работаете, вы ответите — веб-программистом. Но на самом деле было бы правильнее сказать — .NET-программистом, или C#-программистом. Если занимаетесь веб-программированием на .NET, то вполне можете попробовать поднять .NET на Raspberry Pi, и я рекомендую это попробовать. Если вы всю жизнь писали приложения Windows Forms, ничто не мешает вам попробовать написать игру.
.NET сейчас очень активно развивается, что наглядно демонстрирует статистика на слайде. Как видим, C# сейчас входит в 5 наиболее популярных языков на GitHub. На .NET и ASP.NET выполняется очень большой объём работы, то есть происходит много коммитов, много людей участвует в опенсорсных проектах. Интересно, что около 40% новых пользователей .NET — учащиеся. Я очень рад тому, что люди знакомятся с этой платформой в университетах и в школах. А вот другой важный и, возможно, неожиданный показатель развития .NET: в Visual Studio в общей сложности было выполнено более 1 миллиона публикаций на Linux. Работу с .NET на Linux мы ещё обсудим позднее, я расскажу о том, как я портировал свой сайт. У .NET в ближайшем будущем появится новая версия, но .NET 3 тоже вполне хороша, и её будут поддерживать ещё многие годы. Сейчас я рекомендую пользоваться именно ей. Кстати говоря, Stack Overflow недавно перешёл на .NET Core 3.1.
.NET-код
Давайте теперь посмотрим на .NET-код, и для этого откроем командную строку. Конечно, я мог бы показать вам код в Visual Studio, но мне нравится работать именно через командную строку. Это всё равно, что копаться под капотом автомобиля: значительно лучше видно, как он устроен. Итак, я создаю папку myweirddemo
и ввожу в ней команду dotnet new
. В результате на экран выводится список возможных шаблонов и их краткие имена. По большому счёту, это то же самое, что команда File — New Project в Visual Studio. Самое интересное, что здесь можно добавлять свои шаблоны, то есть если я создам опенсорсный проект scott, можно будет ввести команду dotnet new scott
. Изначально в dotnet new
доступны WPF, Windows Forms, специальный проект для Worker, четыре различных плагина для тестирования, а также множество других шаблонов.
Попробуем ввести команду dotnet new console
, а затем откроем текст созданной таким образом программы в блокноте.
Добавим там команду Console.ReadLine()
.
Её исполнение будет приостанавливать исполнение программы. Попробуем вначале запустить программу без этой новой команды. Как видим, вывод простого Hello world занимает у нас 2–3 секунды. Давайте разберёмся, почему так долго. Взглянем на содержимое нашей папки с демкой (команда dir
): как видим, в ней есть папка bin
. Нас будет интересовать исполняемый файл bin\Debug\net5.0\myweirddemo.exe
. Если мы запустим его, то Hello world будет выведено практически мгновенно. То есть команда dotnet run
явно делает что-то ещё помимо исполнения собственно файла программы. Интересно, что в папке с исполняемым файлом также лежит библиотека myweirddemo.dll. Если выполнить dotnet .\myweirddemo.dll
, то мы снова увидим на экране Hello world. Это значит, что программа на самом деле находится в этой библиотеке, а exe-файл сделан исключительно для вашего удобства и спокойствия. В прошлых версиях .NET exe-файл появлялся только после выполнения команды publish.
Итак, вернёмся к dotnet run
. Почему исполнение этой команды занимает больше секунды для такой простой программы? Дело в том, что она вначале вызывает dotnet restore
, затем dotnet build
и лишь затем обращается к dll-файлу программы. Давайте теперь попробуем выполнить нашу программу с добавленной командой .ReadLine()
. Как и ожидалось, программа выводит на экран Hello world, а затем приостанавливает выполнение в ожидании дополнительных команд. Пока она ожидает, откроем Process Explorer — это продвинутый вариант Task Manager, который можно скачать на Sysinternals.
Мы видим дерево запущенных процессов, в котором можно найти процесс нашей команды.
Оговорюсь, что для работы с .NET вовсе не обязательно знать всю ту подноготную, которую мы с вами сейчас исследуем. Но, на мой взгляд, всегда полезно понимать, как работает устройство, которым вы пользуетесь. Чтобы вызвать такси, вовсе не обязательно знать, как устроен автомобиль, но это знание может оказаться полезным, если автомобиль сломается.
Итак, мы видим, что работающий сейчас процесс .NET расположен в C:\Program Files\dotnet\dotnet.exe
.
Перейдём к его местоположению в командной строке. Обратите внимание, что для перехода к другому каталогу я пользуюсь командой z
, а не cd
, она значительно удобнее, поскольку не требует вводить имя каталога целиком. Далее, выполним команду start .
, это откроет Explorer, и мы увидим содержимое папки C:\Program Files\dotnet\sdk
. Здесь будет необходимо небольшое отступление. Прошлые версии .NET работали только под Windows, не были опенсорсными и не поддерживали параллельное выполнение.
Версии .NET
Существовало несколько различных .NET: просто .NET для приложений Windows, Xamarin для мобильных приложений, и кросс-платформенный .NET Core. Поскольку .NET не поддерживал параллельное выполнение, при переходе на более позднюю версию .NET работа приложения, использующего .NET, могла быть нарушена. Xamarin был основан на Mono, это написанная с нуля опенсорсная версия .NET, причём у её создателей не было доступа к исходникам .NET. Мы ещё о ней поговорим чуть позже. А .NET Core была создана специально для обеспечения микросервисов, она заточена под максимальное быстродействие бэкенда.
Ситуация, когда было три различных варианта .NET, была терпимой, но то, к чему мы переходим сейчас — однозначно шаг вперёд. Давайте разберёмся, как устроена новая система версий .NET. В нашей папке sdk
несколько различных версий .NET.
У меня установлена ознакомительная версия .NET 5.0, а также несколько версий .NET 2 и 3, в том числе 3.1 — версия с долгосрочной поддержкой. Вернёмся в папку нашей демки и введём команду dotnet --version
.
Мы увидим, что сейчас мы используем .NET 5. Если мы теперь создадим новую папку для другого проекта, myweirddemo2
, и проверим версию, мы, как и следует ожидать, снова увидим .NET 5.
Взгляните на путь к выполняемому файлу: C:\Program Files\dotnet\dotnet.exe
. В этом пути никак не указана версия .NET. Теперь выполним dotnet new globaljson
. Будет создан файл, который мы откроем в блокноте, и поменяем номер используемой версии .NET.
Обратите внимание, что в папке второй демки нет ничего, кроме этого файла global.json
. Если мы теперь снова проверим версию (dotnet --version
), то увидим, что используется .NET 3.1.300. Затем вернёмся в папку первой демки (myweirddemo)
и проверим версию там: в ней по-прежнему используется 5.0.100. Интересно, не правда ли? Перейдём на рабочий стол и проверим версию там: вновь 5.0.100. Всё дело в том, что у вас может быть множество различных экземпляров .NET. Это очень ценное свойство фреймворка.
В .NET 5 и 6 все три платформы объединены в платформу с единым SDK, единой BCL (базовая библиотека классов) и единым набором инструментов. С помощью этого нового .NET можно будет создавать кросс-платформенные UI, он будет отлично работать в контейнерах и крупномасштабных системах вроде Kubernetes. Что касается времени выхода .NET 5 и 6, новые версии будут выходить каждый год в ноябре, и каждый нечётный год это будут версии с долгосрочной поддержкой. Так что в этом году вы можете поэкспериментировать с .NET 5, а в следующем перейти на .NET 6.
Примечание от организаторов DotNext: про нововведения .NET 5 (от System.Text.Json API до перформансных оптимизаций) на декабрьской конференции будет отдельный доклад Раффаэля Риальди.
Возможности .NET
Вернёмся к нашей демке. Как мы помним, в папке myweirddemo
располагается dll-файл и исполняемый файл демки. А где же собственно .NET? Мы его установили в C:\Program Files\dotnet. Помимо прочего, тут находится папка sdk
с компиляторами и папка shared
с рантаймами. Вообще говоря, любой компьютер всегда стоит загружать по минимуму. Современный .NET весит около гигабайта и требует много ресурсов. Но его не обязательно устанавливать целиком, можно обойтись небольшим рантаймом только с теми компонентами, которые необходимы. Как это сделать? Если я просто скопирую на флешку папку с демкой и вы попробуете её запустить у себя, у вас ничего не выйдет. Предварительно нам нужно будет выполнить команду publish
, тогда мы получим самодостаточное приложение, которое можно запустить, не устанавливая .NET на компьютере.
Прежде чем выполнять publish
, попробуем вначале выполнить dotnet run
. Как видим, команда возвращает ошибку.
Мне нравится, когда такое происходит во время доклада, поскольку это позволяет лучше разобраться в том, что происходит. В данном случае процесс не может получить доступ к dll-файлу, потому что тот используется другим процессом. Закроем программу, в которой открыт этот dll, и повторим команду.
Как видим, всё работает. Теперь выполним dotnet publish -r win-x64
.
Эта команда создала новую папку, перейдём к ней.
Как видим, здесь находится всё необходимое для того, чтобы запустить нашу программу: полная копия .NET, а также выполняемый файл программы и dll-файл. Однако значительная часть файлов .NET для запуска нашей программы не потребуется. Если бы мы писали микросервис, то нам точно следовало бы избавиться от них. Например, нам ни к чему System.Drawing.dll
или System.Globalization.Calendars.dll
. Правда, общий размер нашей папки не такой уж и большой: 65 мегабайт. И всё же 65 мегабайт для Hello world многовато. Организация этих файлов тоже не самая удобная, они просто свалены кучей в одну папку.
Попробуем снова выполнить publish
, но в этот раз добавим несколько параметров к команде: publish -r win-x64 -p:PublishSingleFile=true -p:PublishTrimmed=true
. Откроем получившуюся папку.
Как видим, в ней не осталось ненужного, а вес сократился с 65 мегабайт до 23. Конечно, это несопоставимо с весом программы на C, и для Hello world это по-прежнему много, но не забывайте: здесь содержатся все базовые компоненты .NET. Если наша программа будет вдвое длиннее, её размер не вырастет ещё на 20 мегабайт. Для микросервиса это вполне допустимый вес. И, повторюсь, для запуска этой программы не нужно устанавливать .NET на компьютере.
В начале моего доклада мы с вами рассматривали варианты шаблонов, предлагаемые командой dotnet new
, в их числе были WPF, Windows Forms, Workers и так далее. Представьте теперь, что вы можете сделать приложение с любым из этих шаблонов в виде самодостаточного исполняемого файла, который можно запустить где угодно. Попробуем сделать это с Windows Forms. Это довольно старая платформа, но она пользуется большой популярностью, и с её помощью можно очень быстро создать приложение. Итак, выполним dotnet new winforms
и запустим его: dotnet run
. Перед нами откроется пустое приложение Windows Forms. Предположим, у вас есть приложение, состоящее из текстовых полей поверх данных, которое работает уже 10 или 15 лет. Его можно портировать на .NET Core и запустить как отдельный исполняемый файл. Это позволяет очень легко превратить ваше приложение в сервис или запустить его на чужой машине. Кроме того, при таком подходе не нужно постоянно обновлять версию .NET на машине, где это приложение выполняется. В версии .NET 5 (которая, напомню, является опенсорсной) появится поддержка WPF и Windows Forms, а также некоторых сторонних инструментов, так что унаследованные приложения вроде того, которое мы сейчас обсуждали, можно будет запускать без лишнего труда.
В качестве примера использования .NET я хотел бы показать вам сайт моего подкаста, Hanselminutes. Я делаю этот подкаст уже много лет, в нём больше 700 эпизодов. Если вы перейдёте на домашнюю страницу сайта и прокрутите её до самого низа, то увидите следующую фразу: Powered by .NET Core 3.1.8 and deployed from commit 5bbc4d via build 20200930.1. Мне очень нравится это свойство .NET: на моём сайте запущен собственный экземпляр .NET с долгосрочной поддержкой, и я могу точно указать, из какого коммита он собран и какой номер сборки. Давайте теперь взглянем в Visual Studio на исходный код моего сайта.
Я выделил курсором строку кода, которая возвращает номер используемой версии .NET. Ниже мы получаем номер коммита при помощи git hash. Подробнее обо всём этом написано у меня в блоге.
Приложение для моего подкаста первоначально работало только под Windows, но затем я портировал его на .NET Core, и сейчас использую Razor Pages. Благодаря этому я смог запустить приложение под Linux, а в облаке разместить такое приложение немного дешевле, так что в итоге я сэкономил деньги.
В Visual Studio сейчас видна структура приложения, в нём две главных папки: hanselminutes.core
и hanselminutes.core.tests
. Сборка и тестирование приложения выполняется при помощи скриптов PowerShell. Я это всё рассказываю для того, чтобы продемонстрировать новый образ мышления, к которому приходят в мире .NET. В главной папке с кодом приложения, hanselminutes.core
, есть скрипт .\dockerbuild.ps1, давайте его выполним. Он произведёт сборку приложения при помощи Docker, хотя мы сейчас работаем под Windows. То есть вместо того, чтобы устанавливать .NET под Windows, мы запускаем его SDK внутри docker-контейнера. А это значит, что разработчики .NET могут работать с любым фреймворком в любой операционной системе. Я могу запустить приложение под Windows командой dotnet run
, я могу запустить его на Linux в облаке, или выполнить сборку и тестирование под Linux на моём компьютере. Этой возможности у нас раньше не было. Я могу открыть локальную версию моего подкаста на моём компьютере под Windows и параллельно с этим выполнить скрипт .\dockerrun.psl, который запустит тот же подкаст под Linux. Пока он загружается, я выйду на портал Azure. Там у меня есть панель инструментов, показывающая состояние моей системы. В частности, она отображает запущенные сессии и время использования сервера, а также стоимость используемого времени. Мы можем отобразить информацию по запущенному под Linux в контейнере сервису Hanselminutes.
В данный момент в этом контейнере запущено в общей сложности пять приложений. Это даёт мне экономию где-то в 30%. Я это говорю не к тому, чтобы вы использовали только Linux или только Windows, а к тому, что вы можете пользоваться той системой, которая вам комфортнее. И чем дальше, тем в .NET будет больше такой гибкости.
Кстати говоря, если вы хотите узнать о последних нововведениях в .NET, рекомендую нашу страницу. В частности, там есть встроенный редактор кода, который работает в браузере, то есть для него не нужно устанавливать .NET на компьютер. Хочу также обратить ваше внимание на обучающую страницу, там недавно появился мастер-класс по C#. На этом сайте можно получить сертификаты по представленным там темам. Там же есть онлайн-курсы по C#, .NET и многому другому. Недавно мы выложили там целую книгу по микросервисам, причём она не ограничивается Azure. Книга называется .NET Microservices: Architecture for Containerized .NET Applications. Кроме того, не так давно на этом же сайте было выложено руководство по микросервисам, которое не привязано к Azure. Так что возможности для обучения микросервисам на .NET без Azure вполне есть.
Давайте снова взглянем на приложение, на котором запущен мой подкаст. В сущности, это несколько страниц Razor. Приложение с самого начала писалось на .NET Core, но так обстоит дело далеко не со всеми приложениями. Мой блог был написан 18 лет назад на .NET 2.0, и недавно я обновил его до .NET Core, со всем накопленным за 18 лет материалом. Блог был написан на Web Forms, то есть он работает под Windows, требует запуска виртуальной машины, не масштабируется, перенести его на другой хост я не могу, и у него некрасивые URL-адреса. Сейчас я пишу новый сайт с адресом staging.hanselman.com, который является копией старого, но с .NET Core. Вы можете взять любой адрес с моего старого сайта, заменить www на staging, и попадёте на ту же страницу нового сайта.
Портирование сайта мы делали по частям. Приложение подкаста довольно простое, я его написал за несколько недель. А вот приложение для блога значительно более сложное, у него несколько уровней.
На экране можно увидеть его структуру (das Blog — это «блог» по-немецки). Чтобы портировать приложение, нам было необходимо удалить из него все обращения к Windows. Мы уже обсуждали эту тему в начале доклада: когда мы делаем вызов Console.WriteLine (), у нас происходит обращение к Windows. Если же мы хотим, чтобы приложение было кросс-платформенным, нам нужно убрать из кода всё, что будет работать только в Windows — например, обращения к реестру или использование названия диска C:. Для этой цели существует очень полезный инструмент под названием .NET Portability Analyzer, к нему есть расширение в Visual Studio, но им можно пользоваться и из командной строки. Этот инструмент анализирует приложение и сообщает, насколько оно портируемо и гибко. С помощью этого инструмента мы поняли, что переписать необходимо только фронтенд. Мы разбили фронтенд по паттерну Model — View — Controller.
У моего блога есть база данных, которая представляет собой просто файлы на диске. Когда необходимо отобразить некоторый пост, приложение получает его из базы данных, а затем отображает в качестве страниц Razor, в то время как раньше для этого использовались Web Forms. Портированный блог я смог разместить в облаке, и мне не нужно больше использовать виртуальную машину в качестве хоста. Больше того, я могу запустить это приложение на Linux, в то время как вся разработка шла под Windows. Подробнее о том, как именно я портировал блог, можно прочитать в самом блоге.
Я думаю, что в .NET 5 и 6 этот процесс станет ещё проще, потому что планируется предоставить максимальную поддержку кросс-платформенности, это предоставит разработчикам больше выбора. Кроме того, .NET будет ориентироваться на то, чтобы приложения были как можно меньше. Это значит, что для простого блога не нужно будет поднимать виртуальную машину. Поскольку сейчас всё популярнее становятся Kubernetes, Docker и Docker Compose, растёт потребность в механизмах координации и оркестрации. Для этого мы создаём обратные прокси и Project Tye. Это позволит вам использовать наиболее комфортный для вас инструмент, будь то IIS, Apache, nginx или Azure.
.NET MAUI
Хочу рассказать ещё об одном проекте, над которым сейчас ведётся работа, это .NET MAUI (Multi-Platform App UI, UI для мультиплатформенных приложений). Если вы захотите больше о нём узнать, послушайте мой доклад на Build, он находится в открытом доступе. В основе MAUI лежит мысль о том, что нативный UI можно сделать поверх .NET в рамках одного проекта. В имеющихся сегодня решениях (например, в Xamarin) для этого необходимо создать несколько проектов — один для Android, один для iPhone и так далее. В сущности, MAUI — это следующий этап в эволюции Xamarin.Forms. В конце этого года будут представлены ознакомительные версии MAUI, а окончательный вариант предполагается завершить к выходу .NET 6. Это значит, что в командной строке станет доступна команда dotnet new maui
. В особенности MAUI будет полезен пользователям Xamarin, потому что мы стараемся не менять пространства имён и API для Android и iOS. Если вам нравится Xamarin, то вам ещё больше понравится MAUI.
В общем, в мире .NET сейчас происходит очень много интересного. В ноябре будет проходить виртуальная конференция .NET Conf 2020, она будет привязана к выходу .NET 5. Я её очень рекомендую, сделайте себе пометку в календаре. Что касается .NET 5, то на него не обязательно переходить прямо сейчас, он пока что доступен только в ознакомительной версии. Но его вполне можно запускать параллельно с уже существующим кодом, никак не нарушая работу приложения. Если вы используете версию .NET 3.1 — не переживайте, она будет поддерживаться ещё много лет. Параллельно с ней вы вполне можете протестировать работу ваших приложений с .NET 5, и мы будем очень рады вашим отзывам — вы можете оставить их по адресу dot.net/get-dotnet5. Это позволит нам максимально приблизить .NET 5 и 6 к вашим потребностям и предоставить вам как можно больше возможностей.
Сферы использования .NET
.NET становится всё более универсальной платформой. У себя я также использую .NET для веб-приложений. Его вполне можно разворачивать в облаке. Мы не успели рассмотреть использование .NET на мобильных устройствах, но если вы пользовались Xamarin, то вы уже имеете какое-то об этом представление. А в MAUI мы получим усовершенствованный вариант Xamarin, и с ним можно будет создавать кросс-платформенные приложения на .NET, которые смогут работать где угодно.
Стоит также сказать про сферу применения .NET, о которой часто забывают: игры. Возможно, вы знаете, что Unity работает на C#. Но помимо неё есть отличная опенсорсная платформа MonoGame. О них и о многом другом можно узнать на сайте .NET, там есть специальный раздел, посвященный разработке игр. На этом же сайте есть раздел о машинном обучении. Модели, созданные, скажем, в TensorFlow или ONNX можно преобразовывать в код на .NET. Так что если ваши коллеги занимаются машинным обучением и пишут на Python, вы вполне можете работать с ними, при этом оставаясь на .NET. Что касается десктопных приложений, .NET Core работает с WPF и WinForms.
Есть ещё одна очень интересная область использования .NET Core — это IoT, в частности, Raspberry Pi. Если вы загуглите dotnet raspberry pi и моё имя, то найдёте руководство по созданию кластера Kubernetes на Raspberry Pi.
На кластере запущены приложения ASP.NET. Этот пример демонстрирует, что .NET отлично работает на процессорах ARM. Чтобы дополнительно в этом убедиться, давайте вернёмся к нашей первой демке и выполним в её папке publish -r linux-arm
.
Этой командой мы только что создали на Windows приложение .NET для Raspberry Pi, и нам для этого понадобилось не больше минуты. Новый .NET написан так, чтобы вы могли работать с ним в среде, комфортной именно для вас. Главное, что эта платформа опенсорсная, и у неё очень дружелюбное сообщество. В разделе Community на сайте .NET всегда можно узнать о ближайших конференциях и встречах. Мы всегда рады новым людям, так что пишите нам в Twitter или Stack Overflow. Кроме того, в .NET-сообществе мы проводим онлайн-встречи, и стараемся охватить ими как можно больше часовых поясов, чтобы сделать их доступными для всех, в том числе для наших участников из России. Гости со всего мира выступают у нас с онлайн-докладами о .NET, и им можно задавать вопросы. Мы хотим, чтобы вся наша работа была на виду у сообщества и была максимально открытой для вас.
Это был общий обзор .NET от Скотта Хансельмана, а если вам хочется послушать доклады на более конкретные темы, то стоит заглянуть на сайт следующей конференции DotNext, которая пройдёт в начале декабря. Вот для примера: изменения сборки мусора в .NET 5 осветит Маони Стивенс, которая и отвечает за .NET GC в Microsoft. А также осветим и производительность, и внутреннее устройство платформ, и архитектуру и best practices — каждый .NET-разработчик найдёт там что-то для себя.