Перейти к содержимому

Net cli что это

  • автор:

Создание CLI-приложений при помощи System.CommandLine в .NET

Создание CLI-приложений при помощи System.CommandLine в .NET

В .NET уже несколько лет существует библиотека System.CommandLine, позволяющая быстро создавать CLI-приложения. Несмотря на то, что библиотека ещё в стадии beta, её активно используют и сами разработчики Microsoft, например, в утилите dotnet из пакета .NET SDK.

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

Реализация простого CLI-приложения

Библиотека поддерживает следующие виды токенов:

Опции и аргументы определяются совместно через обобщённый тип Option :

var left = new Option( aliases: new[] < "-l", "--left" >, description: "Left operand") < IsRequired = true, Arity = ArgumentArity.ExactlyOne >; var right = new Option( aliases: new[] < "-r", "--right" >, description: "Right operand") < IsRequired = true, Arity = ArgumentArity.ExactlyOne >;

Полностью исходный код можно найти в нашем GitLab-репозитории.

Subcommand и command отличаются тем, что subcommand определяет группу команд, а command определяет непосредственно действие, выполняемое командой.

Определим для начала команду sum:

var sum = new Command("sum", "Sum of the two numbers"); sum.Add(left); sum.Add(right); sum.SetHandler((l, r) => Console.WriteLine(l + r), left, right);

Разделение на команды и группы команд очень условное, т.к. с точки зрения C# оба вида определяются через класс Command . Также нам ничто не мешает определить действие и для группы команд:

var math = new Command("math", "Mathematical operations"); math.Add(sum); math.SetHandler(() => Console.Write("Math command handler"));

Помимо примитивных типов, библиотека также поддерживает массивы, списки, FileInfo , DirectoryInfo и другие. Полный список можно узнать, заглянув в документацию. Если есть необходимость привязать опции к кастомному типу, то можно воспользоваться встроенным механизмом привязки через тип BinderBase . Определим операцию вычитания, используя этот способ:

public record Subtract(double Left, double Right) < public double Calc() < var result = Left - Right; File.WriteAllText("result.txt", $""); return result; > > public class SubtractBinder : BinderBase  < private readonly Option_left; private readonly Option _right; public SubtractBinder(Option left, Option right) => (_left, _right) = (left, right); protected override Subtract GetBoundValue(BindingContext bindingContext) => new Subtract( bindingContext.ParseResult.GetValueForOption(_left), bindingContext.ParseResult.GetValueForOption(_right)); >

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

subtract.SetHandler( (sub) => Console.WriteLine(sub.Calc()), new SubtractBinder(left, right));

Осталось определить Root command через одноимённый класс RootCommand :

var root = new RootCommand("CLI app example"); root.Add(math); await root.InvokeAsync(args);

Теперь можно собрать приложение и проверить работу:

dotnet run -– math // вывод: Math command handler dotnet run -— math sum -l 4 -r 7 // вывод: 13 dotnet run -— math subtract -l 10 -r 3 // вывод: 7

Внедрение зависимостей

Жизненный цикл CLI-приложения выглядит следующим образом:

  1. Вызывается некоторая команда.
  2. Запускается процесс.
  3. Происходит обработка данных, возвращается результат.
  4. Процесс завершается.

Классические контейнеры зависимостей не рекомендуется использовать, поскольку зависимости одной команды могут быть совершенно не нужны для другой команды, а инициализация всех зависимостей может увеличить время запуска CLI-приложения. Вместо этого можно воспользоваться механизмом внедрения зависимостей для конкретного обработчика. Для этого снова понадобится класс BinderBase . Определим новый класс ResultWriter , который будет записывать результат математической операции в файл:

public class ResultWriter < public void Write(double result) =>File.WriteAllText("result.txt", $""); >

Теперь создадим класс ResultWriterBinder . Этот класс инкапсулирует экземпляр ResultWriter :

public class ResultWriterBinder : BinderBase  < private readonly ResultWriter _resultWriter = new ResultWriter(); protected override ResultWriter GetBoundValue(BindingContext bindingContext) =>_resultWriter; >

Теперь определим операцию умножения и внедрим туда экземпляр ResultWriter :

var multiply = new Command("multiply", "Multiply one number by another"); multiply.Add(left); multiply.Add(right); multiply.SetHandler((left, right, resultWriter) => < var result = left * right; resultWriter.Write(result); Console.WriteLine(result); >, left, right, new ResultWriterBinder());

Такой подход позволяет внедрять зависимости в обработчики команд независимо друг от друга.

Кастомизация вывода

Справка генерируется автоматически из описаний, которые использовались при инициализации опций и команд. Например, команда cli-app math sum -h отобразит следующее:

Description: Sum of the two numbers Usage: cli-app math sum [options] Options: -l, --left (REQUIRED) Left operand -r, --right (REQUIRED) Right operand -?, -h, --help Show help and usage information

При желании можно заменить любой раздел справки, например, Description или создать новый. Добавим новую строку с текстом «This is a new section» в начало справки:

using System.CommandLine.Builder; using System.CommandLine.Help; using System.CommandLine.Parsing; // остальной код var parser = new CommandLineBuilder(root) .UseDefaults() .UseHelp(ctx => ctx.HelpBuilder.CustomizeLayout(x => HelpBuilder.Default .GetLayout() .Prepend(d => Console.WriteLine("This is a new section")))) .Build();

Тогда вывод станет следующим:

This is a new section Description: Sum of the two numbers // остальной текст

Если требуется улучшить внешний вид вывода данных в целом, то сделать это можно, например, написав кастомный способ отображения при помощи методов и свойств класса Console, таких как SetCursorPosition, ForegroundColor, BackgroundColor и т.д. Либо воспользоваться 3rd-party библиотеками:

1. ShellProgressBar. Простая библиотека для отображения прогресса в командном окне.

2. Spectre.Console. Мощная библиотека для создания красивых консольных приложений, которая имеет множество компонентов, упрощающих создание интерфейса. Кстати, обложка для статьи была сделана с помощью этой библиотеки.

3. ConsoleGUI. Позволяет создавать полноценный GUI на основе консоли. Судя по всему, автор вдохновлялся WPF, так как в ней содержатся привычные для этого фреймворка компоненты: TextBox, CheckBox, DataGrid, DockPanel и другие.

Заключение

Библиотека System.CommandLine является полезным инструментом для создания CLI-приложений. Она даёт разработчикам гибкий инструментарий для работы командами и опциями, что позволяет сократить время разработки и создать удобный и функциональный пользовательский интерфейс.

Net cli что это

Создадим первую программу на ASP.NET Core. Что нам для этого потребуется? Прежде всего необходим текстовый редактор для написания кода программы. В данном случае я буду использовать в качестве текстового редактора Visual Studio Code

Также для компиляции и запуска программы нам потребуется .NET SDK. Для его установки перейдем на официальный сайт по ссылке .NET SDK

Загрузка .NET SDK для ASP.NET Core

C:\dotnet\aspnet\helloapp . Откроем терминал/командную строку и перейдем к созданной папке проекта с помощью команды cd

cd C:\dotnet\aspnet\helloapp

В данном случае мы для создания и запуска проекта мы будем использовать встроенную инфраструктуру .NET CLI, которая устанавливается вместе с .NET SDK.

Для создания проекта в .NET CLI применяется команда dotnet new , после которой указывается тип проекта. Для ASP.NET Core есть ряд встроенных типов проектов. В данном случае мы будем использовать самый простейший тип — web . Поэтому введем в терминале команду

dotnet new web

Создание первого проекта ASP.NET Core и C# с помощью .NET CLI

Структура проекта ASP.NET Core

Рассмотрим базовую структуру простейшего стандартного проекта ASP.NET Core:

  • Dependencies : все добавленные в проект пакеты и библиотеки, иначе говоря зависимости
  • Properties : узел, который содержит некоторые настройки проекта. В частности, в файле launchSettings.json описаны настройки запуска проекта, например, адреса, по которым будет запускаться приложение.
  • appsettings.json : файл конфигурации приложения в формате json
  • appsettings.Development.json : версия файла конфигурации приложения, которая используется в процессе разработки
  • helloapp.csproj : стандартный файл проекта C#, который соответствует назанию проекта (по умолчанию названию каталога) и описывает все его настройки.
  • Program.cs : главный файл приложения, с которого и начинается его выполнение. Код этого файла настраивает и запускает веб-приложение

Например, посмотрим на содержимое файла helloapp.csproj

  net8.0 enable enable   

Ключевой компонент здесь — атрибут Sdk=»Microsoft.NET.Sdk.Web» , который собственно и определяет, что приложение будет использовать SDK «Microsoft.NET.Sdk.Web», который предназначен именно для веб-проектов.

Запуск проекта

Проект по умолчанию не представляет какой-то грандиозной функциональности, тем не менее этот проект мы уже можем запустить. Итак, запустим проект. Для этого выполним команду

dotnet run

запуск проекта ASP.NET Core и C# с помощью .NET CLI

При запуске в консоли мы можем увидеть адрес, по которому мы можем обращаться к приложению. В моем случае это адрес «http://localhost:5204». И я могу обратиться по этому адресу к приложению в браузере и увидеть в нем строку «Hello World!» — результат работы кода по умолчанию из файла Program.cs :

Первое приложение на ASP.NET Core на С# с .NET CLI

Запуск приложения и файл Program.cs

Рассмотрим код файла Program.cs , который создает подобное приложение:

var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();

Это так называемое Minimal API — упрощенная минизированная модель для запуска веб-приложения в ASP.NET.

Приложение в ASP.NET Core представляет объект Microsoft.AspNetCore.Builder.WebApplication . Этот объект настраивает всю конфигурацию приложения, его маршруты, используемые зависимости и т.д.. Исходный код класса на github: https://github.com/dotnet/aspnetcore/blob/main/src/DefaultBuilder/src/WebApplication.cs

Для создания объекта WebApplication необходим специальный класс-строитель — WebApplicationBuilder . И в файле Program.cs вначале создается данный объект с помощью статического метода WebApplication.CreateBuilder :

var builder = WebApplication.CreateBuilder(args);

В качестве параметра в метод передаются аргументы, которые передаются приложению при запуске.

Получив объект WebApplicationBuilder , у него вызывается метод Build() , который собствено и создает объект WebApplication :

var app = builder.Build();

С помощью объекта WebApplication можно настроить всю инфраструктуру приложения — его конфигурацию, маршруты и так далее. В файле Program.cs по умолчанию для приложения определяется один маршрут:

app.MapGet("/", () => "Hello World!");

Метод MapGet() в качестве первого параметра принимает путь, по которому можно обратиться к приложению. В данном случае это путь «/», то есть по сути корень веб-приложения — имя домена и порта, после которых может идти слеш, например, https://localhost:7256/

В качестве второго параметра в метод MapGet() передаются обработчик запроса по этому маршруту в виде функции. Здесь это лямбда-выражение, которое возвращает строку «Hello World!». Именно поэтому при обращении к приложению мы увидим данную строку в браузере.

И в конце необходимо запустить приложение. Для этого у класса WebApplication вызывается метод Run() :

app.Run();

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

Интерфейс командной строки — Основы командной строки

Представьте, что вы изучаете новую для себя программу. Вы запускаете ее, читаете названия пунктов меню, нажимаете на разные кнопки и получаете какой-нибудь результат. В этот момент вы взаимодействуете с графическим интерфейсом — так же его называют GUI или Graphical User Interface.

Но GUI — это не единственный существующий интерфейс. В этом уроке мы изучим интерфейс командной строки (CLI или Command Line Interface). Такой интерфейс может показаться непривычным, ведь в нем нет ничего, кроме названия программы.

Аргументы и опции

Чем чаще вы будете использовать командную строку, тем больше различных программ вам встретится. Многие из них станут повседневными инструментами. Например, вы часто будете пользоваться программой ls , которая выводит на экран список файлов и директорий.

Здесь все просто. Достаточно набрать название программы и нажать Enter :

ls Desktop Documents Downloads Library Movies Music Pictures Public 

Еще мы можем посмотреть скрытые файлы и директории. В *nix-системах они начинаются с точки: .profile .

Тогда необходимо набрать ls -a :

ls -a . .CFUserTextEncoding Desktop Downloads Movies Pictures .. .localized Documents Library Music Public 

А если захотим посмотреть содержимое каталога Public? Тогда мы воспользуемся командой ls с аргументом:

ls Public Drop Box 

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

-i input.mp4 -vcodec libx264 -crf 30 output.mp4 

В этом уроке нам пока не нужно детально разбираться во всех подробностях таких сложных примеров. Главное — увидеть закономерности в использовании консольных программ.

Хорошая новость в том, что закономерности есть. Плохая новость — не все четко следуют им.

Практически любую команду можно дополнить двумя способами:

Способ 1 — это аргументы. Для примера рассмотрим команду ls Music , которая содержит аргумент Music

Способ 2 — это опции, еще их иногда называют флагами. Например, команда ls -a содержит в себе опцию -a

Опции

Поговорим подробнее об опциях. Они всегда начинаются с одного или двух дефисов. Одна из часто используемых опций для просмотра списка файлов — -l . Она выводит дополнительную информацию по каждому файлу:

ls -l total 0 drwx------+ 3 Guest _guest 96 Nov 21 2017 Desktop drwx------+ 3 Guest _guest 96 Nov 21 2017 Documents drwx------+ 3 Guest _guest 96 Nov 21 2017 Downloads drwx------+ 26 Guest _guest 832 Nov 21 2017 Library drwx------+ 3 Guest _guest 96 Nov 21 2017 Movies drwx------+ 3 Guest _guest 96 Nov 21 2017 Music drwx------+ 3 Guest _guest 96 Nov 21 2017 Pictures drwxr-xr-x+ 4 Guest _guest 128 Nov 21 2017 Public 

Опции можно комбинировать. Представим, что мы хотим увидеть список всех файлов, включая скрытые, причем с подробным описанием. В таком случае нужно набрать команду ls -a -l . Можно объединить эти опции и записать ту же команду вот так:

При работе с опциями не забывайте ставить — . Без него вы получите команду ls la в которой la — это аргумент, а не опция. В таком случае командная оболочка покажет содержимое директории la .

Еще мы можем использовать опции и аргументы одновременно, хотя все зависит от программы. В случае с ls можно использовать одновременно и то, и другое. Чтобы просмотреть полное содержимое директории Music с информацией о каждом файле, можно набрать команду ls -la Music :

ls -la Music total 0 drwx------+ 4 Guest _guest 128 Nov 21 2017 . drwxr-xr-x+ 89 Guest _guest 2848 Aug 24 14:06 .. -rw-r--r-- 1 Guest _guest 0 Nov 21 2017 .localized drwxr-xr-x 9 Guest _guest 288 Aug 26 17:25 iTunes 

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

Иногда сложно понять подобные записи: -tupa . Не совсем понятно, что это:

  • Одна опция tupa
  • Четыре опции t , u , p и a , объединенные в одну цепочку

В таких ситуациях нужно смотреть документацию соответствующей программы. Это можно сделать с помощью команды man (сокращение от manual). Достаточно набрать man — и мы попадем в режим чтения документации.

В мануале содержится описание утилиты в целом, формат ее вызова, все возможные опции, примеры вызовов и много другой полезной информации:

Попробуйте прямо сейчас посмотреть мануал программы ls , набрав в терминале man ls . Перемещаться внутри мануала можно так:

  • Промотать вперед — f (forward)
  • Промотать назад — b (backward)
  • Выход из режима просмотра — q (quit)

Еще полезен сайт explainshell . На нем можно вбить любую команду и посмотреть удобное интерактивное описание:

Варианты опций

У большинства утилит есть два варианта одной и той же опции — длинная и короткая версия. Например, в PHP есть -v и —version :

-v PHP 7.2.7 (cli) (built: Jun 22 2018 06:27:50) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies php --version PHP 7.2.7 (cli) (built: Jun 22 2018 06:27:50) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies 

Длинные и короткие версии опций используются в разных ситуациях:

  • Когда мы работаем в терминале, важно набирать быстро — там удобны короткие опции
  • Когда мы пишем скрипт из разных команд, важно писать понятно — лучше использовать длинные опции. Так с первого взгляда очевидно, что означает каждая опция

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

Опции, которые мы рассматривали выше, не имеют параметров. Но нередко встречаются опции, которые недостаточно просто указать.

Например, в macOS есть встроенная утилита say . Если просто передать ей какой-то текст, то она его произнесет. Можно пойти дальше и записать произнесенный текст в файл.

Чтобы это сделать, надо указать опцию -o и записать путь до файла:

# Вместо -o можно написать --output-file say -o hi.aac 'Hello, World.' 

В этом примере путь до файла — это значение опции, обычно оно указывается через пробел от самой опции.

Если значение опции содержит в себе специальные или пробельные символы, то его нужно оборачивать в кавычки, двойные или одинарные:

-o 'hi.aac' 'Hello, World.' 

Некоторые программы допускают использование знака = вместо пробела:

# Команда say такое не позволяет, но зато видно принцип say -o=hi.aac 'Hello, World.' 

Кроме того, say позволяет указать входной файл, который нужно прочитать. Если он указан, то say проигнорирует передаваемый текст как аргумент:

# Здесь мы указали входной файл, который нужно прочитать — hello_world.txt # Еще здесь указано, каким голосом надо читать и в какой файл записывать прочитанное say -v Alex -o hi -f hello_world.txt 

Теперь посмотрим на документацию программы say , а именно в раздел SYNOPSIS. Там мы увидим все доступные возможности:

[-v voice] [-r rate] [-o outfile [audio format options] | -n name:port | -a device] [-f file | string . ] 

Такое подробное описание есть практически у любой утилиты. Описания построены по одному и тому же принципу:

  • Квадратные скобки [] обозначают необязательность. Например, опция -v необязательна, то же самое касается и любых других опций этой программы
  • Вертикальная черта | обозначает операцию «исключающее или». Посмотрите на последний блок [-f file | string . ] . Он означает, что say может либо произносить текст из файла, либо произносить строчку, переданную как аргумент. Сделать оба варианта одновременно не получится

Бывают и другие вариации описания способов вызова: значение по умолчанию, выбор из конкретных элементов, отрицание.

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

Дополнительные материалы
  1. Построение приложений командной строки (CLI)
  2. Справочник по командной оболочке

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Обзор интерфейса командной строки .NET

Интерфейс командной строки (CLI) .NET — это кроссплатформенная цепочка инструментов для разработки, сборки, запуска и публикации приложений .NET.

Интерфейс командной строки .NET входит в пакет SDK для .NET. Сведения об установке пакета SDK для .NET см. в статье Установка .NET Core.

Команды CLI

По умолчанию устанавливаются следующие команды:

Основные команды

Команды для изменения проекта

  • add package
  • add reference
  • remove package
  • remove reference
  • list reference

Расширенные команды

Команды управления средством

  • tool install
  • tool list
  • tool update
  • tool restore (доступна, начиная с пакета SDK для .NET Core 3.0)
  • tool run (доступна, начиная с пакета SDK для .NET Core 3.0)
  • tool uninstall

Средства — это консольные приложения, которые устанавливаются из пакетов NuGet и вызываются из командной строки. Вы можете писать средства самостоятельно или устанавливать средства, написанные другими. Средства также называются глобальными средствами, средствами пути к средству и локальными средствами. Дополнительные сведения см. в обзоре средств .NET.

Структура команд

Структура команд CLI состоит из драйвера («dotnet»), самой команды и ее возможных аргументов и параметров. Этот шаблон используется в большинстве операций интерфейса командной строки, таких как создание консольного приложения и его запуск из командной строки, как показывают следующие команды при выполнении из каталога my_app:

dotnet new console dotnet build --output ./build_output dotnet ./build_output/my_app.dll 

Драйвер

Драйвер называется dotnet и имеет два вида ответственности — выполнение платформозависимого приложения или выполнение команды.

Для запуска платформозависимого приложения укажите его драйвера, например dotnet /path/to/my_app.dll . При выполнении команды из папки, где находится библиотека DLL приложения, просто выполните dotnet my_app.dll . Если вы хотите использовать конкретную версию среды выполнения .NET, используйте параметр —fx-version (см. справку по —fx-version ).

При указании команды для драйвера dotnet.exe запускает процесс выполнения команды CLI. Пример:

dotnet build 

Сначала драйвер определяет нужную версию пакета SDK. Если файл global.json отсутствует, используется последняя доступная версия пакета SDK. Это может быть предварительная или стабильная версия, в зависимости от того, какая версия является последней на компьютере. После определения версии пакета SDK он выполняет команду.

Команда

Команда выполняет действие. Например, dotnet build проводит сборку кода. dotnet publish публикует код. Команды реализуются как консольное приложение с использованием соглашения dotnet .

Аргументы

Аргументы, указываемые в командной строке, передаются непосредственно в вызываемую команду. Например, если выполнить dotnet publish my_app.csproj , аргумент my_app.csproj указывает публикуемый проект и передается в команду publish .

Параметры

Параметры, указываемые в командной строке, передаются непосредственно в вызываемую команду. Например, при выполнении dotnet publish —output /build_output параметр —output и его значение передаются в команду publish .

См. также

  • Репозиторий GitHub dotnet/sdk
  • Руководство по установке .NET

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *