Oop

Package Management (Управління Пакетами)

Package Management (Управління Пакетами)

Передумови: Рекомендується ознайомитись з основами .NET CLI перед вивченням цього розділу.

Навіщо це потрібно?

Уявіть, що ви створюєте веб-додаток. Вам потрібно працювати з JSON, логувати події, підключатися до бази даних, відправляти HTTP-запити... Писати весь цей код з нуля — марнування часу. Натомість, ви використовуєте готові бібліотеки (packages), які вирішують ці задачі.

Але як керувати десятками залежностей? Як оновлювати їх? Як переконатися, що всі члени команди використовують однакові версії? Саме для цього існує NuGet — система управління пакетами для .NET.

Що таке NuGet?

NuGet (вимовляється "New Get") — це офіційний менеджер пакетів для платформи .NET. Він дозволяє:

  • 📦 Встановлювати бібліотеки (пакети) в проєкт одією командою
  • 🔄 Оновлювати залежності до нових версій
  • 🔍 Шукати серед понад 350,000 доступних пакетів
  • 📤 Публікувати власні бібліотеки для використання іншими розробниками
  • 🔒 Керувати версіями та залежностями автоматично
Loading diagram...
graph TD
    A[Ваш Проєкт] -->|dotnet add package| B[NuGet]
    B -->|Завантажує| C[NuGet.org]
    B -->|Завантажує| D[Приватний Feed]
    B -->|Завантажує| E[Локальна Папка]

    C -->|Пакет + Залежності| A
    D -->|Пакет + Залежності| A
    E -->|Пакет + Залежності| A

    style A fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style B fill:#64748b,stroke:#334155,color:#ffffff
    style C fill:#f59e0b,stroke:#b45309,color:#ffffff
    style D fill:#64748b,stroke:#334155,color:#ffffff
    style E fill:#64748b,stroke:#334155,color:#ffffff

Еволюція Package Management у .NET

Використовувався в .NET Framework

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
  <package id="Serilog" version="3.1.1" targetFramework="net48" />
</packages>

Проблеми:

  • Пакети копіювалися в папку packages/ у кожному проєкті
  • Складне управління транзитивними залежностями
  • Великий розмір репозиторіїв

Джерела Пакетів (Package Sources)

NuGet може завантажувати пакети з різних джерел:

1. Офіційний Репозиторій — NuGet.org

NuGet.org — це публічний безкоштовний репозиторій, де розміщено понад 350,000 пакетів.

# Пошук пакетів на NuGet.org
dotnet search Serilog

# Або через веб-інтерфейс
# https://www.nuget.org/packages
Best Practice: Завжди перевіряйте Downloads, GitHub Stars, та Last Update пакета перед використанням. Популярні пакети зазвичай краще підтримуються.

2. Приватні Feeds

Для корпоративних проєктів часто використовують приватні репозиторії:

Azure DevOps Artifacts — інтегрується з Azure pipelines.

# Додати приватний feed
dotnet nuget add source https://pkgs.dev.azure.com/yourorg/_packaging/yourfeed/nuget/v3/index.json \
  --name AzureArtifacts \
  --username anything \
  --password <YOUR_PAT>
Безпека: Ніколи не зберігайте паролі безпосередньо в nuget.config. Використовуйте:
  • Environment Variables
  • Azure Key Vault
  • GitHub Secrets
  • Credential Providers

3. Локальні Feeds

Корисні для розробки та тестування пакетів локально:

# Додати локальну папку як джерело пакетів
dotnet nuget add source /Users/yourname/local-packages --name LocalFeed

# Або на Windows
dotnet nuget add source C:\local-packages --name LocalFeed

Конфігурація nuget.config

Всі джерела пакетів зберігаються в файлі nuget.config:

nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/yourorg/_packaging/yourfeed/nuget/v3/index.json" />
    <add key="LocalFeed" value="/Users/yourname/local-packages" />
  </packageSources>

  <packageSourceCredentials>
    <AzureArtifacts>
      <add key="Username" value="anything" />
      <add key="ClearTextPassword" value="%AZURE_ARTIFACTS_PAT%" />
    </AzureArtifacts>
  </packageSourceCredentials>
</configuration>

Встановлення Пакетів

Існує три основні способи встановлення NuGet пакетів:

1. Використання .NET CLI (Рекомендовано)

Встановлення останньої версії

[`dotnet add package`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package) Newtonsoft.Json

Ця команда:

  1. Знаходить останню стабільну версію пакета на NuGet.org
  2. Додає <PackageReference> в .csproj файл
  3. Автоматично виконує dotnet restore

Встановлення конкретної версії

dotnet add package Newtonsoft.Json --version 13.0.3

Встановлення prerelease версії

dotnet add package Microsoft.EntityFrameworkCore --prerelease

Встановлення з певного джерела

dotnet add package YourCompany.Core --source https://your-private-feed.com/nuget

Встановлення для конкретного target framework

dotnet add package System.Text.Json --framework net8.0

2. Package Manager UI (Visual Studio / Rider)

У Visual Studio та JetBrains Rider є графічний інтерфейс для управління пакетами:
  • Visual Studio: Tools → NuGet Package Manager → Manage NuGet Packages for Solution
  • Rider: Right-click on project → Manage NuGet Packages

3. Ручне редагування .csproj

Ви можете безпосередньо редагувати файл проєкту:

MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="Serilog" Version="3.1.1" />
    <PackageReference Include="FluentValidation" Version="11.9.0" />
  </ItemGroup>
</Project>
Після ручного редагування виконайте:
dotnet restore

Управління Залежностями

Транзитивні Залежності

Коли ви встановлюєте пакет, він може мати власні залежності. NuGet автоматично їх завантажує:

Loading diagram...
graph TD
    A[Ваш Проєкт] --> B[Serilog.AspNetCore 8.0.0]
    B --> C[Serilog 3.1.0]
    B --> D[Serilog.Extensions.Hosting 8.0.0]
    B --> E[Serilog.Formatting.Compact 2.0.0]

    D --> C
    E --> C

    style A fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
    style B fill:#f59e0b,stroke:#b45309,color:#ffffff
    style C fill:#64748b,stroke:#334155,color:#ffffff
    style D fill:#64748b,stroke:#334155,color:#ffffff
    style E fill:#64748b,stroke:#334155,color:#ffffff

Це називається транзитивні залежності (transitive dependencies). NuGet автоматично розв'язує всі залежності та завантажує правильні версії.

Перегляд Дерева Залежностей

# Показати всі пакети проєкту
[`dotnet list package`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-list-package)

# Показати транзитивні залежності
dotnet list package --include-transitive

# Показати дерево у вигляді JSON
dotnet list package --format json

Приклад виводу:

Project 'MyWebApp' has the following package references
   [net8.0]:
   Top-level Package                            Requested   Resolved
   > Serilog.AspNetCore                         8.0.0       8.0.0

   Transitive Package                           Resolved
   > Serilog                                    3.1.0
   > Serilog.Extensions.Hosting                 8.0.0
   > Serilog.Formatting.Compact                 2.0.0

Конфлікти Версій

Що трапляється, якщо два пакети вимагають різні версії однієї залежності?

<!-- Пакет A потребує Newtonsoft.Json 12.0 -->
<PackageReference Include="PackageA" Version="1.0.0" />

<!-- Пакет B потребує Newtonsoft.Json 13.0 -->
<PackageReference Include="PackageB" Version="2.0.0" />
Compatibility Risk: Примусове використання новішої версії може спричинити проблеми, якщо PackageA не сумісний з Newtonsoft.Json 13.0. Завжди тестуйте після зміни версій!

Перевірка Вразливостей

NuGet дозволяє перевіряти пакети на відомі вразливості безпеки:

# Показати пакети з відомими вразливостями
dotnet list package --vulnerable

# Показати застарілі пакети
dotnet list package --deprecated

Приклад виводу:

The following sources were used:
   https://api.nuget.org/v3/index.json

Project `MyWebApp` has the following vulnerable packages
   [net8.0]:
   Top-level Package      Requested   Resolved   Severity   Advisory URL
   > System.Text.Json     6.0.0       6.0.0      High       https://github.com/advisories/GHSA-...
Security Alert: Якщо виявлено вразливість з рівнем High чи Critical, оновіть пакет якнайшвидше!

Оновлення Пакетів

Перевірка Застарілих Пакетів

# Показати всі застарілі пакети
dotnet list package --outdated

# Тільки major updates
dotnet list package --outdated --highest-major

# Тільки minor updates
dotnet list package --outdated --highest-minor

Приклад виводу:

Project `MyWebApp` has the following updates to its packages
   [net8.0]:
   Top-level Package              Requested   Resolved   Latest
   > Newtonsoft.Json              12.0.3      12.0.3     13.0.3
   > Serilog                      2.10.0      2.10.0     3.1.1

Семантичне Версіонування (SemVer)

NuGet використовує Semantic Versioning (SemVer) у форматі MAJOR.MINOR.PATCH:

КомпонентКоли змінюєтьсяПриклад
MAJORBreaking changes (несумісні зміни API)1.0.02.0.0
MINORНова функціональність (зворотно сумісна)1.0.01.1.0
PATCHBug fixes (виправлення помилок)1.0.01.0.1
Update Strategy:
  • 🟢 PATCH — завжди безпечно оновлювати
  • 🟡 MINOR — зазвичай безпечно, але перевірте release notes
  • 🔴 MAJOR — потребує ретельного тестування, можливі breaking changes

Діапазони Версій

Ви можете вказати діапазон прийнятних версій:

<!-- Точна версія -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<!-- Мінімальна версія (13.0.3 або вище) -->
<PackageReference Include="Newtonsoft.Json" Version="[13.0.3,)" />

<!-- Діапазон версій (від 13.0.0 до 14.0.0, не включно) -->
<PackageReference Include="Newtonsoft.Json" Version="[13.0.0,14.0.0)" />

<!-- Wildcard для patch версії -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.*" />
Trade-off: Використання діапазонів забезпечує гнучкість, але може призвести до недетермінованих білдів (різні розробники отримують різні версії). Для production рекомендується фіксувати точні версії.

Lock Files (Фіксація Версій)

Для забезпечення відтворюваності білдів використовуйте lock files:

MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
  </PropertyGroup>
</Project>

Це створить файл packages.lock.json, який фіксує точні версії всіх залежностей:

packages.lock.json
{
    "version": 1,
    "dependencies": {
        "net8.0": {
            "Newtonsoft.Json": {
                "type": "Direct",
                "requested": "[13.0.3, )",
                "resolved": "13.0.3",
                "contentHash": "HJQJXkjsRHxC..."
            }
        }
    }
}

Створення та Публікація Приватних Пакетів

Час створити власний NuGet пакет!

Крок 1: Структура бібліотеки

Крок 4: Створення Пакета

# Створення NuGet пакета (.nupkg файл)
[`dotnet pack`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack) --configuration Release

# Результат: bin/Release/MyCompany.Core.1.0.0.nupkg

Крок 5: Публікація

# Потрібен API ключ з https://www.nuget.org/account/apikeys
[`dotnet nuget push`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push) bin/Release/MyCompany.Core.1.0.0.nupkg \
  --api-key YOUR_API_KEY \
  --source https://api.nuget.org/v3/index.json
Versioning Best Practice:
  • Використовуйте SemVer послідовно
  • Автоматизуйте версіонування через CI/CD (наприклад, GitVersion)
  • Додавайте release notes до кожної версії

Global Tools (Глобальні Інструменти)

.NET Global Tools — це консольні додатки, які можна встановити глобально та викликати з будь-якого місця в терміналі.

Встановлення Global Tools

# Встановлення інструменту глобально
dotnet tool install --global dotnet-ef

# Після встановлення можна викликати з будь-якого місця
dotnet ef --version

Популярні Global Tools

ІнструментПризначенняВстановлення
dotnet-efEntity Framework CLIdotnet tool install --global dotnet-ef
dotnet-outdatedПеревірка застарілих пакетівdotnet tool install --global dotnet-outdated-tool
dotnet-formatCode formatterdotnet tool install --global dotnet-format
dotnet-tracePerformance profilingdotnet tool install --global dotnet-trace
dotnet-dumpMemory dump analysisdotnet tool install --global dotnet-dump

Local Tools (Tool Manifests)

Замість глобальної установки, можна використовувати локальні інструменти на рівні проєкту:

Створення Manifest

# Створити .config/dotnet-tools.json
dotnet new tool-manifest

Встановлення Local Tool

# Встановити інструмент локально
dotnet tool install dotnet-ef

Використання

# Виклик локального інструменту
dotnet tool run dotnet-ef --version

# Або просто
dotnet ef --version

Переваги Local Tools:

  • ✅ Версія інструменту зберігається в репозиторії
  • ✅ Всі члени команди використовують однакову версію
  • ✅ Не конфліктує з глобальними установками

Приклад dotnet-tools.json:

.config/dotnet-tools.json
{
    "version": 1,
    "isRoot": true,
    "tools": {
        "dotnet-ef": {
            "version": "8.0.0",
            "commands": ["dotnet-ef"]
        },
        "dotnet-outdated-tool": {
            "version": "4.6.0",
            "commands": ["dotnet-outdated"]
        }
    }
}

Управління Global Tools

# Показати всі встановлені глобальні інструменти
dotnet tool list --global

# Оновити інструмент
dotnet tool update --global dotnet-ef

# Видалити інструмент
dotnet tool uninstall --global dotnet-ef

# Встановити інструмент у кастомну папку
dotnet tool install dotnet-ef --tool-path ~/my-tools

Практична Реалізація: Створення Проєкту з Пакетами

Давайте створимо реальний проєкт, який використовує кілька популярних пакетів:

Створення Web API проєкту

dotnet new webapi -n ProductCatalog
cd ProductCatalog

Встановлення пакетів

# Entity Framework Core для роботи з БД
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design

# Serilog для логування
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console

# FluentValidation для валідації
dotnet add package FluentValidation.AspNetCore

# Swagger для API документації (вже включено в шаблон webapi)

Перевірка встановлених пакетів

dotnet list package

Вивід:

Project 'ProductCatalog' has the following package references
   [net8.0]:
   Top-level Package                                    Requested   Resolved
   > FluentValidation.AspNetCore                        11.3.0      11.3.0
   > Microsoft.EntityFrameworkCore.Design               8.0.0       8.0.0
   > Microsoft.EntityFrameworkCore.Sqlite               8.0.0       8.0.0
   > Serilog.AspNetCore                                 8.0.0       8.0.0
   > Serilog.Sinks.Console                              5.0.1       5.0.1
   > Swashbuckle.AspNetCore                             6.5.0       6.5.0

Структура Web API проєкту

Restore пакетів

# Завантажити всі пакети та залежності
dotnet restore

Troubleshooting (Вирішення Проблем)

Проблема 1: "Package not found"

Симптоми:

error NU1101: Unable to find package 'SomePackage'. No packages exist with this id in source(s): nuget.org

Рішення:

Перевірте назву пакета

# Пошук на NuGet.org
dotnet tool install --global dotnet-search
dotnet-search SomePackage

Перевірте джерела пакетів

dotnet nuget list source

Додайте потрібне джерело

dotnet nuget add source https://your-custom-feed.com/nuget --name CustomFeed

Проблема 2: Version Conflicts

Симптоми:

error NU1107: Version conflict detected for 'Newtonsoft.Json'.
 PackageA 1.0.0 -> Newtonsoft.Json (>= 12.0.0)
 PackageB 2.0.0 -> Newtonsoft.Json (>= 13.0.0)

Рішення:

<!-- Явно вказати версію, яка задовольняє обидва пакети -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

Проблема 3: Restore Failures

Симптоми:

error : The restore operation failed. Check the console output for details.

Рішення:

# Очистити кеш NuGet
dotnet nuget locals all --clear

# Повторити restore з детальним логуванням
dotnet restore --verbosity detailed

# Видалити bin/ і obj/ папки
rm -rf bin obj
dotnet restore

Проблема 4: Authentication Failures (Private Feeds)

Симптоми:

error : Response status code does not indicate success: 401 (Unauthorized)

Рішення:

# Встановити Azure Artifacts Credential Provider
# https://github.com/microsoft/artifacts-credprovider

# Або використати PAT (Personal Access Token)
dotnet nuget update source AzureArtifacts \
  --username anything \
  --password YOUR_PAT \
  --store-password-in-clear-text
Security: Параметр --store-password-in-clear-text зберігає пароль у відкритому вигляді. Для production використовуйте Credential Providers або Azure Key Vault!

Завдання для Практики

📝 Level 1: Основи (Beginner)

🔧 Level 2: Середній (Intermediate)

🚀 Level 3: Просунутий (Advanced)