От нуля до сборки: пошаговое руководство
В этой теме представлен практический пошаговый гид по использованию Lino CLI в качестве основного инструмента при создании проекта: от установки и первоначальной настройки, через генерацию сервисов, модулей и сущностей, до продвинутых функций, таких как события, фоновые задачи, миграции, сборка Docker-образов и управление версиями.
Цель — показать интегрированным образом, как команды CLI вписываются в реальный процесс разработки — не просто перечислить их, а объяснить причины каждого выбора, что генерируется автоматически и каковы архитектурные последствия.
Даже если у каждой команды есть собственная документация, здесь вы увидите процесс от начала до конца — воспроизводимый сценарий, который экономит часы повторяющейся работы и помогает поддерживать согласованный и тестируемый код.
В ходе руководства мы объясним технические концепции, применяемые в Lino (например: CQRS, TypedResults, Source Generators, Outbox Pattern), покажем примеры команд и укажем лучшие практики для управления версиями, деплоя и непрерывной интеграции.
Установка и настройка Lino CLI
Первый шаг для начала работы с Lino CLI — установить инструмент в вашей среде разработки. Он распространяется как dotnet глобальный инструмент, что означает, что он будет доступен для любого проекта .NET на вашем компьютере.
Шаг 1: Установка
Чтобы установить (или обновить) Lino CLI, выполните следующую команду в терминале:
dotnet tool install --global Tolitech.Lino
Важные замечания:
- Если версия уже установлена, можно использовать
dotnet tool update --global Tolitech.Linoдля обновления. - Убедитесь, что директория глобальных инструментов .NET находится в системном
PATH, чтобы командаlinoработала корректно.
Шаг 2: Настройка языка
После установки рекомендуется настроить язык (или культуру), который CLI будет использовать в сообщениях, подсказках и логах:
lino preferences culture set
Вам будет предложено выбрать один из доступных языков. Эта настройка гарантирует, что все инструкции и подсказки будут отображаться последовательно на выбранном языке.
Шаг 3: Аутентификация и регистрация
Чтобы получить доступ ко всем возможностям Lino, включая расширенные шаблоны, публикацию Docker-образов и интеграцию с внешними сервисами, необходимо пройти аутентификацию.
- Если у вас еще нет учетной записи, зарегистрируйтесь с помощью команды:
lino user register
- Если учетная запись уже есть, войдите с помощью:
lino auth login
Что происходит: CLI сохраняет токен аутентификации локально, позволяя выполнять команды, требующие доступа к защищённым ресурсам, без повторного входа.
Шаг 4: Проверка
Чтобы убедиться, что установка и аутентификация прошли успешно, выполните:
lino --version
Если команда вернула установленную версию, вы готовы начать использовать Lino CLI в своих проектах.
Создание проекта MyApp
На этом шаге мы создадим начальную структуру проекта с использованием Lino CLI. Этот проект будет служить основой для демонстрации создания сервисов, модулей, фронтенда и всей интеграции событий.
Шаг 1: Выполнение команды создания
Чтобы создать новый проект, выполните следующую команду в терминале:
lino project new
CLI будет пошагово направлять вас, запрашивая следующую информацию:
- Название проекта: мы используем
MyApp, но вы можете выбрать любое другое имя; - Дополнительные функции: анализаторы кода, распределённый кэш, поддержка асинхронных событий и др.
Шаг 2: Настройка основных функций
Для этого проекта рекомендуется включить следующие функции с самого начала:
- Анализаторы кода: обеспечивают соблюдение кода лучших практик и единых стандартов, предотвращая распространённые ошибки реализации;
- Распределённый кэш: улучшает производительность приложения в сценариях с несколькими сервисами, предотвращая ненужные запросы к базе данных;
- Асинхронная коммуникация: включает использование событий и очередей для интеграции между сервисами, обеспечивая масштабируемость и разъединение компонентов.
Включение всех этих опций в проекте важно, так как мы будем создавать несколько сервисов, которые будут взаимодействовать через интеграционные события. Это позволит вам понять, как строить модульные и распределённые системы с использованием Lino.
Шаг 3: Сгенерированная структура
После выполнения команды и настройки функций CLI создаст начальную структуру проекта, которая будет включать:
- Папки для сервисов и модулей;
- Шаблоны для фронтенда (если применимо);
- Начальные настройки кэша, событий и интеграций;
- Файлы решения (.slnx) и проекта (.csproj), готовые к компиляции.
Теперь ваш проект MyApp готов для добавления сервисов, модулей, сущностей и фронтенда, которые мы будем настраивать на следующих шагах.
Добавление фронтенда
Теперь мы создадим интерфейс системы — фронтенд, который будет использоваться как Backoffice. Этот фронтенд не будет публичным приложением, а станет внутренним инструментом, позволяющим администраторам и менеджерам управлять продуктами, категориями, запасами, продажами и другой информацией системы.
Шаг 1: Выполнение команды создания
Чтобы добавить новый фронтенд в проект, используйте следующую команду в терминале:
lino webapp new
В процессе работы CLI запросит некоторые данные, например:
- Имя веб-приложения: в этом примере мы используем
Backoffice;
Шаг 2: Сгенерированная структура
По завершении процесса CLI сгенерирует начальную структуру фронтенда внутри папки WebApps/Backoffice.
Стандартная структура включает:
- Папки для страниц, компонентов и сервисов приложения;
- HTTP-клиенты для работы с API сервисов проекта;
- Начальные шаблоны;
- Файлы конфигурации для интеграции с аутентификацией, авторизацией и системными событиями.
Важные замечания
- Фронтенд будет автоматически интегрирован с выбранными сервисами и модулями, что позволит напрямую использовать данные о продуктах, категориях и продажах через API, сгенерированные Lino.
- Можно создавать несколько фронтендов, например, один для администраторов (Backoffice) и другой — публичный (Site), используя тот же процесс.
С созданием фронтенда мы готовы перейти к созданию сервисов и модулей, которые будут предоставлять данные и бизнес-логику для этого приложения.
Создание сервисов и модулей
На этом этапе мы создадим сервисы и модули, которые будут составлять приложение. Цель — построить модульную и масштабируемую архитектуру, позволяющую различным областям системы, таким как продукты, категории, склад, продажи и медиа, развиваться независимо, при этом сохраняя согласованность и облегчая поддержку.
Шаг 1: Определение сервисов
Сначала создадим следующие сервисы с чётко определёнными обязанностями:
- Catalog (модульный) – управление продуктами, категориями и ценами;
- Sales – обработка продаж и заказов;
- Stock – управление складом и движением товаров;
- Security – аутентификация, авторизация и управление пользователями.
Для создания нового сервиса выполните команду:
lino service new
Во время выполнения команды CLI запросит:
- Имя сервиса: например,
Catalog; - База данных: выберите технологию, наиболее подходящую для вашего проекта (SQL Server, PostgreSQL и т.д.);
Шаг 2: Создание модулей внутри сервисов
Не все сервисы должны быть модульными. В нашем проекте только сервис Catalog будет иметь модули, чтобы разделить обязанности, такие как мерчандайзинг и ценообразование.
Для сервиса Catalog определены следующие модули:
- Merchandising – управление продуктами и категориями;
- Pricing – управление ценами, акциями и историей изменений.
Для создания модуля выполните команду:
lino module new
Вы можете создать любое количество модулей внутри модульного сервиса Catalog. Кроме того, в зависимости от сложности, некоторые модули в будущем могут стать независимыми сервисами. Представленное здесь разделение носит учебный характер и служит примером модульной организации.
Окончательная структура проекта
После создания сервисов и модулей ваша структура решения должна быть примерно следующей:
MyApp/
└── src/
├── Aspire/
├── Integrations/
├── Services/
│ ├── Catalog/
│ │ ├── Modules/
│ │ │ ├── Merchandising/
│ │ │ └── Pricing/
│ │ ├── MyApp.Catalog.Host
│ │ └── MyApp.Catalog.Infrastructure
│ ├── Sales/
│ ├── Security/
│ ├── Shared/
│ └── Stock/
└── WebApps/
├── Backoffice/
│ ├── Services/
│ │ ├── Catalog/
│ │ ├── Sales/
│ │ ├── Security/
│ │ └── Stock/
│ ├── MyApp.WebApp.Backoffice
│ └── MyApp.WebApp.Backoffice.Client
└── Shared/
└── MyApp.WebApp.Shared
└── tests/
└── Services/
├── Catalog/
│ ├── Merchandising/
│ └── Pricing/
├── Sales/
├── Security/
├── Shared/
└── Stock/
Объяснение структуры:
Services/: содержит все сервисы системы, каждый из которых изолирован и имеет свою бизнес-логику, инфраструктуру и хостинг;Modules/: папки внутри модульных сервисов, позволяющие организовывать конкретные функции и поддерживать связный код;WebApps/: фронтенды, связанные с системой и интегрированные с сервисами;Shared/: библиотеки и ресурсы, общие для сервисов и фронтендов;tests/: модульные и интеграционные тесты, организованные по сервисам и модулям.
Благодаря этой модульной структуре каждая команда или разработчик может работать независимо над разными частями системы, облегчая масштабирование, поддержку и тестирование.
Добавление аутентификации и авторизации
Аутентификация и авторизация являются ключевыми элементами любой современной системы. В Lino CLI их добавление в проект простое и быстрое.
Шаг 1: Выполнение команды аутентификации
Чтобы добавить функции аутентификации и авторизации, используйте команду:
lino features auth add
CLI проведет вас через следующие этапы:
- Выбор сервиса или модуля: необходимо указать, куда будут установлены компоненты аутентификации. В нашем примере мы используем сервис Security, который централизует всю логику безопасности системы;
- Дополнительные настройки: создание таблиц пользователей, ролей и прав, а также настройка политик доступа.
Шаг 2: Сгенерированная структура
После выполнения команды сервис Security будет содержать файлы и папки, такие как:
- Entities: классы пользователей, ролей и прав;
- Infrastructure: конфигурации базы данных и миграции для создания таблиц;
- Application: сервисы аутентификации, управления пользователями и проверки учетных данных;
- API/Host: конечные точки для входа, выхода, регистрации и управления ролями.
С этой настройкой ваше приложение будет иметь надежную аутентификацию и детализированный контроль доступа, готовое поддерживать нескольких пользователей и разные уровни прав.
Добавление фоновых задач
В распределённых и модульных системах, таких как та, что мы строим с помощью Lino CLI, не все сервисы общаются напрямую друг с другом. Для обеспечения согласованности и надёжности при обмене информацией мы используем интеграционные события. Однако для эффективной и асинхронной обработки этих событий нам нужны фоновые задачи (Background Jobs).
Lino использует Outbox Pattern, чтобы гарантировать, что все сообщения, создаваемые сервисами, надёжно фиксируются перед отправкой. Это позволяет:
- Избежать потери событий в случае сбоя или перезапуска сервиса;
- Обеспечить отправку одного и того же сообщения только один раз;
- Позволить повторную обработку сообщений в случае сбоя доставки;
- Разделить обработку событий и основную логику приложения, улучшая производительность и масштабируемость.
Шаг 1: Выполнение команды
Чтобы добавить поддержку фоновых задач в проект, выполните команду:
lino features background-job add
CLI попросит вас выбрать сервис, в котором будет установлен Background Job. Обычно выбирают сервис, который централизует создание событий, например Catalog или Sales.
Шаг 2: Настройка выполнения
Во время настройки вы можете определить:
- Интервал проверки: определяет, как часто Background Job будет проверять таблицу Outbox на наличие новых сообщений. Слишком короткий интервал увеличивает использование ресурсов, слишком длинный может задерживать доставку событий;
- Размер пакета обрабатываемых записей: контролирует, сколько событий будет прочитано и отправлено за одно выполнение. Большие пакеты могут повысить производительность, но требуют больше памяти и вычислительной мощности;
- Политика повторной отправки: в случае сбоя доставки сообщений можно настроить количество повторных попыток отправки задачи.
Эти параметры зависят от размера системы, возможностей машины и ожидаемого объёма событий.
Шаг 3: Сгенерированная структура
После настройки проект будет иметь Background Job, готовый обрабатывать сообщения из таблиц Outbox в каждом сервисе.
Это гарантирует, что все интеграционные события обрабатываются надежно и эффективно, позволяя нескольким сервисам и модулям общаться асинхронно без влияния на производительность основной системы.
Создание сущностей и перечислений
В этом разделе мы подробно рассмотрим проектирование сущностей, перечислений и объектов-значений в приложении, показывая, в каких службах и модулях создается каждый элемент.
1. Создание сущности Category
Чтобы создать сущность, используйте команду:
lino entity new
Сущность будет создана в службе Catalog и модуле Merchandising со следующей структурой:
┌────┬────┬───────────────┬────────┬────────┬──────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼────────┼────────┼──────────┼────────────────┤ │ x │ │ Id │ Guid │ │ x │ x │ ├────┼────┼───────────────┼────────┼────────┼──────────┼────────────────┤ │ │ │ Name │ string │ 50 │ x │ │ └────┴────┴───────────────┴────────┴────────┴──────────┴────────────────┘
2. Создание сущности Product
Далее создаем сущность Product в той же службе и модуле, включая объекты-значения и перечисления:
┌────┬────┬───────────────┬─────────────┬────────┬──────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ x │ │ Id │ Guid │ │ x │ x │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ │ Name │ string │ 100 │ x │ │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ │ Description │ string │ 500 │ x │ │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ │ Price │ decimal │ │ x │ │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ x │ CategoryId │ Category │ │ x │ │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ │ Dimensions │ ValueObject │ │ │ │ ├────┼────┼───────────────┼─────────────┼────────┼──────────┼────────────────┤ │ │ │ Status │ Enum │ │ x │ │ └────┴────┴───────────────┴─────────────┴────────┴──────────┴────────────────┘
2.1 Создание объекта-значения ProductDimension
Этот объект-значение представляет размеры продукта:
┌───────────────┬─────────┬────────┬──────────┐ │ Property name │ Type │ Length │ Required │ ├───────────────┼─────────┼────────┼──────────┤ │ Width │ decimal │ │ x │ ├───────────────┼─────────┼────────┼──────────┤ │ Height │ decimal │ │ x │ ├───────────────┼─────────┼────────┼──────────┤ │ Depth │ decimal │ │ x │ └───────────────┴─────────┴────────┴──────────┘
2.2 Создание перечисления ProductStatus
Это перечисление определяет статус продукта:
┌───────┬──────────────┬──────────────┐ │ Value │ Name │ Display Name │ ├───────┼──────────────┼──────────────┤ │ 1 │ Active │ Active │ ├───────┼──────────────┼──────────────┤ │ 2 │ Inactive │ Inactive │ ├───────┼──────────────┼──────────────┤ │ 3 │ Discontinued │ Discontinued │ └───────┴──────────────┴──────────────┘
3. Добавление новых свойств
По мере развития проекта мы можем редактировать существующие сущности, чтобы добавлять новые свойства.
Например, добавим список изображений в сущность Product:
lino entity edit
Создавая свойство Images типа List<ProductImage>, мы получим следующую структуру:
┌────┬────┬───────────────┬────────────────────┬────────┬──────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ x │ │ Id │ Guid │ │ x │ x │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ │ Name │ string │ 100 │ x │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ │ Description │ string │ 500 │ x │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ │ Price │ decimal │ │ x │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ x │ CategoryId │ EntityId │ │ x │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ │ Dimensions │ ValueObject │ │ │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ │ Status │ Enum │ │ x │ │ ├────┼────┼───────────────┼────────────────────┼────────┼──────────┼────────────────┤ │ │ x │ Images │ List<ProductImage> │ │ │ │ └────┴────┴───────────────┴────────────────────┴────────┴──────────┴────────────────┘
3.1 Создание сущности ProductImage
Эта сущность принадлежит агрегату Product и имеет следующую структуру:
┌────┬────┬───────────────┬────────────────┬────────┬──────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤ │ x │ │ Id │ Guid │ │ x │ x │ ├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤ │ │ x │ ProductId │ EntityId │ │ x │ │ ├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤ │ │ │ UploadDate │ DateTimeOffset │ │ x │ │ ├────┼────┼───────────────┼────────────────┼────────┼──────────┼────────────────┤ │ │ │ Image │ File │ │ x │ │ └────┴────┴───────────────┴────────────────┴────────┴──────────┴────────────────┘
4. Создание сущностей для других служб
В службе Sales мы создаем сущность ProductSnapshot, которая будет наполняться событиями интеграции.
Поскольку исходный Id сущности Product приходит из службы Catalog, здесь он не может быть автоинкрементным.
┌────┬────┬───────────────┬─────────┬────────┬──────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤ │ x │ │ Id │ Guid │ │ x │ │ ├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤ │ │ │ Name │ string │ 100 │ x │ │ ├────┼────┼───────────────┼─────────┼────────┼──────────┼────────────────┤ │ │ │ Price │ decimal │ │ x │ │ └────┴────┴───────────────┴─────────┴────────┴──────────┴────────────────┘
Примечание: только необходимые поля были скопированы в ProductSnapshot для службы Sales. Дополнительные сущности, такие как Customer, Order и StockItem, здесь не рассматриваются для упрощения документации.
Создание событий и их обработчиков
Напомним, в предыдущем разделе мы создали в модульном сервисе Catalog.Merchandising сущности Product, Category и ProductImage, а в сервисе Sales — сущность ProductSnapshot.
Теперь мы создадим доменные события и интеграционные события. Цель состоит в том, чтобы при создании или обновлении продуктов в сервисе Catalog эти изменения реплицировались в потребляющие сервисы, такие как Sales и Stock.
1. Создание доменных событий
Первый шаг — создать доменные события ProductCreated и ProductUpdated с помощью команды:
lino event new
Во время создания можно связать событие с обработчиком и одновременно настроить триггер интеграционного события. Это централизует создание всего необходимого потока.
┌──────────────────────────────────────────────────────┬────────────────────────────────┐ │ Question │ Answer │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a service: │ Catalog │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a module: │ Merchandising │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a entity: │ Product │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select the event type: │ Domain Event │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Enter the name of the event: │ ProductCreated │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Do you want to create an associated event handler? │ Yes │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Trigger a integration event? │ Yes │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Choose the integration event to be triggered: │ (Create new integration event) │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Enter the name of the event: │ ProductCreated │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Which model will be used for this integration event? │ Creation model │ └──────────────────────────────────────────────────────┴────────────────────────────────┘
Аналогично создаём событие ProductUpdated:
┌──────────────────────────────────────────────────────┬────────────────────────────────┐ │ Question │ Answer │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a service: │ Catalog │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a module: │ Merchandising │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select a entity: │ Product │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Select the event type: │ Domain Event │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Enter the name of the event: │ ProductUpdated │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Do you want to create an associated event handler? │ Yes │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Trigger a integration event? │ Yes │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Choose the integration event to be triggered: │ (Create new integration event) │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Enter the name of the event: │ ProductUpdated │ ├──────────────────────────────────────────────────────┼────────────────────────────────┤ │ Which model will be used for this integration event? │ Update model │ └──────────────────────────────────────────────────────┴────────────────────────────────┘
Таким образом, мы имеем:
- Созданные доменные события (
ProductCreatedиProductUpdated); - Соответствующие обработчики доменных событий;
- Интеграционные события, автоматически зарегистрированные в Outbox обработчиком доменных событий.
2. Создание обработчиков интеграционных событий
Следующий шаг — определить, какие сервисы будут потреблять интеграционные события. Для этого используется команда:
lino event-handler new
Поток создания включает:
- Выбор сервиса, модуля и сущности, в которой будет находиться обработчик;
- Выбор интеграционного события, которое будет потребляться, и из какого сервиса/модуля/сущности оно пришло.
Например, в сервисе Sales мы создаём обработчики для ProductCreated и ProductUpdated, которые будут потреблять события, генерируемые Catalog.Merchandising.Product:
┌────────────────────────────────────────────┬───────────────────┐ │ Question │ Answer │ ├────────────────────────────────────────────┼───────────────────┤ │ Select a service: │ Sales │ ├────────────────────────────────────────────┼───────────────────┤ │ Select a entity: │ ProductSnapshot │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event type: │ Integration Event │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's service to be consumed: │ Catalog │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's module to be consumed: │ Merchandising │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's entity to be consumed: │ Product │ ├────────────────────────────────────────────┼───────────────────┤ │ Choose the event to be consumed: │ ProductCreated │ ├────────────────────────────────────────────┼───────────────────┤ │ Enter the name of the event handler: │ ProductCreated │ └────────────────────────────────────────────┴───────────────────┘
┌────────────────────────────────────────────┬───────────────────┐ │ Question │ Answer │ ├────────────────────────────────────────────┼───────────────────┤ │ Select a service: │ Sales │ ├────────────────────────────────────────────┼───────────────────┤ │ Select a entity: │ ProductSnapshot │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event type: │ Integration Event │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's service to be consumed: │ Catalog │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's module to be consumed: │ Merchandising │ ├────────────────────────────────────────────┼───────────────────┤ │ Select the event's entity to be consumed: │ Product │ ├────────────────────────────────────────────┼───────────────────┤ │ Choose the event to be consumed: │ ProductUpdated │ ├────────────────────────────────────────────┼───────────────────┤ │ Enter the name of the event handler: │ ProductUpdated │ └────────────────────────────────────────────┴───────────────────┘
Таким образом, в сервисе Sales мы имеем два обработчика интеграционных событий, которые потребляют только необходимые поля из интеграционных событий Catalog.Merchandising. Это гарантирует, что реплицированные таблицы содержат только ключевые данные, оптимизируя хранение и производительность.
Генерация веб-страниц, API, Commands и Queries
Одним из больших преимуществ Lino CLI является возможность автоматизированного создания веб-страниц, API, Commands и Queries, упрощая весь процесс разработки. Чтобы начать, просто выполните команду:
lino page new
В процессе вы:
- Выберете сервис, модуль и сущность, которые хотите опубликовать;
- Выберете поля, которые будут отображаться в списке;
- Автоматически создадите страницы списка (пагинированная сетка) и формы создания/редактирования;
- Сгенерируете классы HttpClient для использования на фронтенде;
- Создадите все необходимые REST API (POST, PUT, PATCH, DELETE и GET);
- Создадите Commands и Queries с соответствующими Handlers, которые взаимодействуют с базой данных, обеспечивая полный CRUD-процесс.
С этой командой вы получаете полностью функциональное приложение без необходимости вручную писать слой интерфейса, API и бизнес-логику, сохраняя стандарты и согласованность между сервисами.
Для этого проекта мы можем сгенерировать интегрированные страницы для следующих сущностей:
- Catalog.Merchandising.
Category - Catalog.Merchandising.
Product - Sales.
ProductSnapshot
После генерации страниц, API и Commands/Queries приложение будет готово для полной интеграции между фронтендом и бэкендом, с проверками, маршрутами и сохранением данных, уже настроенными автоматически Lino CLI.
Создание миграций базы данных
Теперь, когда все сущности созданы, пора сгенерировать миграции, чтобы базы данных были созданы или обновлены в соответствии с определённой моделью. Lino CLI автоматизирует этот процесс, интегрируясь с Entity Framework и создавая готовые к выполнению скрипты.
Чтобы создать новую миграцию, выполните команду:
lino database migrations new
Во время выполнения вам потребуется:
- Выбрать сервис и модуль, для которых будет создана миграция;
- Указать описание миграции, например, "Initial migration".
┌───────────────────────────────────────────┬───────────────────┐ │ Question │ Answer │ ├───────────────────────────────────────────┼───────────────────┤ │ Select a service: │ Catalog │ ├───────────────────────────────────────────┼───────────────────┤ │ Select a module: │ Merchandising │ ├───────────────────────────────────────────┼───────────────────┤ │ Current version of the service: │ 0.1.0 │ ├───────────────────────────────────────────┼───────────────────┤ │ Provide a description for this migration: │ Initial migration │ └───────────────────────────────────────────┴───────────────────┘
После подтверждения Lino CLI сгенерирует:
- Новую миграцию базы данных для текущей версии сервиса;
- Соответствующий SQL-скрипт, расположенный в слое Infrastructure.Persistence, по пути /scripts/<version>/<имя файла>;
- Запись версии миграции в истории сервиса, обеспечивая отслеживаемость и согласованность.
Рекомендуемые практики:
- Создавайте новые миграции каждый раз, когда изменяется модель данных (новые сущности, свойства или изменения связей);
- Проверяйте сгенерированные SQL-скрипты перед применением в продакшене;
- Поддерживайте контроль версий базы данных синхронизированным с версией приложения, чтобы избежать конфликтов и проблем синхронизации.
Следуя этому процессу, вы обеспечиваете, что база данных всегда актуальна и соответствует модели домена, определённой в Lino CLI, снижая количество ошибок и упрощая сопровождение.
Создание Docker-образов
После завершения генерации кода для конкретной версии, проведения тестов и реализации всех необходимых бизнес-правил, вы можете создать Docker-образы для сервисов и веб-приложений вашего проекта для последующей публикации в реестре контейнеров.
Lino CLI упрощает этот процесс с помощью команды:
lino build
При выполнении вы увидите список всех доступных в проекте сервисов и веб-приложений с их текущими версиями:
Select the services or web applications you want to include in the build:
> [ ] Services
[ ] Catalog |0.1.0|
[ ] Sales |0.1.0|
[ ] Security |0.1.0|
[ ] Stock |0.1.0|
[ ] Web applications
[ ] Backoffice |0.1.0|
Вы можете выбрать один или несколько сервисов и веб-приложений для одновременного создания образов. Просто отметьте нужные элементы.
Далее потребуется выбрать, как обновлять версию создаваемых образов. Доступные варианты:
- Сохранить текущую версию – версия не изменяется;
- Patch – увеличить патч-версию (например: 0.1.0 → 0.1.1);
- Minor – увеличить минор-версию (например: 0.1.0 → 0.2.0);
- Major – увеличить мажор-версию (например: 0.1.0 → 1.0.0).
После выбора сервисов и способа увеличения версии, Lino CLI выполнит:
- Сборку кода каждого сервиса и веб-приложения;
- Создание соответствующего Docker-образа;
- Присвоение тегов с указанной версией;
- Предоставление образов для публикации в вашем реестре контейнеров.
В конце процесса, если все сервисы и веб-приложения были выбраны, созданные образы будут иметь следующую структуру:
- my-app/services/catalog-host - tag: 0.1.0
- my-app/services/sales-api - tag: 0.1.0
- my-app/services/security-api - tag: 0.1.0
- my-app/services/stock-api - tag: 0.1.0
- my-app/webapps/backoffice - tag: 0.1.0
Примечание: Этот процесс обеспечивает согласованность между кодом и версиями Docker-образов, облегчая деплой и обслуживание нескольких окружений, а также позволяя каждому сервису работать в отдельном контейнере.
Создание версий в приложении
Увеличение версий сервисов или веб-приложений — это простой процесс, централизованный в Lino CLI. Достаточно выполнить команду:
lino version bump
Как и при создании Docker-образов, при выполнении этой команды вы увидите полный список всех сервисов и веб-приложений вашего проекта. Только выбранные элементы будут иметь увеличенную версию, остальные останутся без изменений.
Select the services or web applications that will have version changes:
> [ ] Services
[ ] Catalog |0.1.0|
[ ] Sales |0.1.0|
[ ] Security |0.1.0|
[ ] Stock |0.1.0|
[ ] Web applications
[ ] Backoffice |0.1.0|
После выбора необходимых элементов вам будет предложено выбрать тип увеличения версии. Доступные варианты:
- Patch – небольшие исправления без функционального воздействия;
- Minor – добавление новых функций, совместимых с предыдущими версиями;
- Major – изменения, которые могут нарушить совместимость с предыдущими версиями.
Важно отметить, что версии сервисов и веб-приложений напрямую влияют на:
- Теги Docker-образов;
- Папки для хранения скриптов, сгенерированных при миграциях базы данных;
- Контроль релизов и история проекта.
На этом мы завершаем пошаговое руководство по всем основным командам для создания веб-проекта с использованием Lino CLI, включая установку, создание сервисов, сущностей, событий и страниц, а также генерацию Docker-образов и управление версиями.
Не забудьте подписаться на наш канал YouTube, чтобы смотреть подробные руководства, практические демонстрации и советы по использованию инструмента, от простых операций до продвинутых функций.
