Категорія: Uncategorized

  • Збій Azure Front Door – 29 жовтня

    Оскільки ми говоримо про Azure Front Door (AFD), варто згадати збій, що стався 29 жовтня.

    Для тих, хто не знайомий з AFD: це глобальний балансувальник навантаження рівня 7 (Layer 7). Він має безліч точок присутності (PoPs) по всьому світу.

    Як це працює:

    • Клієнт підключається до найближчої точки присутності.

    • Використовується Split TCP, який завершує TLS-сесію локально для швидшої відповіді.

    • AFD отримує контент із здорового бекенду.

    • Підтримує кешування та інтеграцію з Web Application Firewall (WAF).

    Цей сервіс широко використовується як Microsoft-сервісами (наприклад, Office 365, Xbox, Entra), так і сторонніми постачальниками.

    Причина збою та вирішення

    Збій спричинила зміна конфігурації тенанта, яка випадково створила некоректний стан конфігурації, що зробило велику кількість вузлів “нездоровими”.

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

    Microsoft уже виявила та усунула помилку в програмному забезпеченні, яка дозволила обійти захисні перевірки при розгортанні некоректної конфігурації.

    Що можуть зробити клієнти

    З архітектурної точки зору: як можна самостійно мінімізувати ризики?

    • Azure Front Door — це глобальний балансувальник навантаження, але як резервний варіант можна розглянути Azure Traffic Manager.
      Однак слід врахувати:

      • Traffic Manager базується на DNS;

      • Він не має можливостей WAF, кешування або Split TCP;

      • Не підтримує приватні ендпоїнти чи непублічні сервіси.

    Отже, хоча це не повна альтернатива, Traffic Manager може бути “аварійним рішенням” у надзвичайних ситуаціях.

    Microsoft серйозно інвестує у запобігання подібним інцидентам, адже вони впливають не лише на клієнтів, а й на сервіси самої компанії — M365, Minecraft тощо.

  • Топ-5 нових функцій у C# 14, які варто спробувати

    C# 14 принес с собой множество обновлений, делающих код чище, безопаснее и выразительнее. После тестирования я выделил пять лучших нововведений, хотя одно из них вызывает у меня сомнения. Давайте разберём всё по порядку.

    1. Null-условное присваивание

    В предыдущих версиях, например C# 13, приходилось вручную проверять объект на null перед присвоением значений свойствам:

    if (channel != null) channel.Subscribers = 1000;

    Рабочий, но громоздкий вариант.

    Теперь, в C# 14, можно использовать null-условное присваивание, что делает код гораздо лаконичнее:

    channel?.Subscribers = 1000;

    Эта запись безопасно выполнит присваивание только если channel не равен null. Чисто и просто.

    2. Ключевое слово field для резервных полей

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

    private int _subscribers; public int Subscribers { get => _subscribers; set => _subscribers = value; }

    В C# 14 появилось ключевое слово field, позволяющее избавиться от лишних переменных:

    public int Subscribers { get => field; set { if (value < 1000) throw new Exception("Недостаточно подписчиков!"); field = value; } }

    Теперь код выглядит компактнее, а вы всё так же можете добавлять нужную логику в setter.

    3. Пользовательские составные операторы

    Эта функция действительно впечатляет. В C# 14 появились пользовательские составные операторы, с помощью которых можно переопределять такие операторы, как + или ++ для своих классов.

    Пример:

    public static Channel operator +(Channel c) { c.Subscribers++; c.Members++; return c; }

    Теперь достаточно просто написать:

    channel++;

    И оба свойства — Subscribers и Members — увеличатся автоматически. Просто и красиво.

    4. Новый ключевой оператор extension

    Методы-расширения давно стали неотъемлемой частью C#, но их синтаксис выглядел немного устаревшим. Раньше это выглядело так:

    public static class ChannelExtensions { public static void PrintDetails(this Channel channel) { Console.WriteLine($"Subs: {channel.Subscribers}, Members: {channel.Members}"); } }

    Теперь в C# 14 можно использовать новое ключевое слово extension напрямую при определении расширения:

    public extension Channel { public void PrintDetails() => Console.WriteLine($"Subs: {Subscribers}, Members: {Members}"); }

    Работает так же, только выглядит современнее.
    Правда, у меня к этой функции двоякое отношение: она добавляет гибкость, но может внести путаницу в синтаксис между версиями C#.

    5. Улучшенный nameof для открытых обобщённых типов

    Теперь оператор nameof поддерживает открытые обобщённые типы, чего раньше не было.

    В C# 13 следующая запись не работала:

    nameof(Channel<>);

    А вот в C# 14 — работает и возвращает "Channel".

    Изменение небольшое, но полезное при генерации кода, рефлексии и диагностике.

    Итоги

    C# 14 предлагает отличный набор улучшений и синтаксического сахара.
    Null-условное присваивание и пользовательские составные операторы — безусловные фавориты, а ключевое слово field делает определение свойств современнее.

    Новый синтаксис с extension всё ещё спорный, но в целом язык развивается в правильном направлении.

  • Уразливість Microsoft .NET із рейтингом 9.9 викликала глобальне занепокоєння: що насправді відбувається

    Це найвищий показник уразливості в історії .NET — приголомшливі 9.9 балів. Проблема залишається відкритою вже тиждень, і спільнота розробників активно обговорює, що відбувається. Розберімося детальніше, чому навколо цього такий галас і що це означає для компаній і програмістів у всьому світі.

    Щоб зрозуміти масштаб

    Для порівняння пригадаймо уразливість Log4J — настільки серйозну, що про неї повідомляли навіть BBC News. Тоді її рейтинг становив 10.0, тобто максимальний рівень за шкалою CVSS. Microsoft навіть профінансувала професійний документальний фільм про те, наскільки небезпечною була подія з Log4Shell.

    Тепер Microsoft оголосила про уразливість у .NET із рейтингом 9.9, майже на рівні Log4J. Це одразу викликало хвилю тривоги, непорозумінь і безліч незручних розмов у IT-відділах по всьому світу.

    Як це виглядає на практиці

    Типовий діалог цього тижня виглядає приблизно так:

    Керівник: «Ця нова уразливість у .NET із рейтингом 9.9 з’явилася на моїй супердорогій панелі безпеки “Executive Security Dashboard 3000”. Пам’ятаєш Log4J чотири роки тому? Там було 10. Це майже те саме. Ми в небезпеці?»

    Full-stack програмист: «Все гаразд, босе. Команда .NET уже випустила патч».

    Керівник: «Ця проблема існує в .NET роками. Як ми можемо знати, що нас уже не зламали?»

    Прогамист: «Ми не знаємо…»

    І саме в цьому головна проблема — немає жодних офіційних рекомендацій від команди безпеки .NET. Розробники не знають, де шукати ознаки атаки, як перевірити факт зламу або чи взагалі вони уразливі.

    Так, можна перевірити логи — якщо ви їх зберігали — але на цьому все закінчується.

    Відсутність чітких відповідей

    Не дивно, що така невизначеність викликала обурення у спільноті. На GitHub розробники напряму звертаються до інженерів Microsoft, зокрема до Баррі Доранса, але його відповіді не додають впевненості.

    Ось кілька прикладів:

    • Питання: Чи уразливий застосунок, якщо він розміщений під IIS? Чи пом’якшує IIS цю проблему?
      Відповідь: «Це питання до команди продукту IIS. Я не можу говорити від їхнього імені.»
    • Питання: Чи допомагає Azure Front Door (веб-фаєрвол Microsoft) пом’якшити цю уразливість?
      Відповідь: «Це питання до команди Azure Front Door. Я не можу говорити від їхнього імені.»
    • Питання: Коли Azure App Service оновить свій runtime?
      Відповідь: «Це питання до команди Azure App Service. Я не можу говорити від їхнього імені.»
    • Питання: Чи буде патч для .NET 6?
      Відповідь: «Ні, цей реліз більше не підтримується.»

    А коли розробники попросили навести конкретні приклади можливої експлуатації, відповідь була коротка:

    «Як я вже сказав вище — ні.»

    Azure App Service все ще працює на уразливій версії

    Через тиждень після публікації уразливості перевірка нових екземплярів Azure App Service показала, що вони досі працюють на .NET 8.0.16, де є вразливість. Безпечна версія — 8.0.21 — досі не розгорнута.

    Це викликає подив, враховуючи, як швидко Microsoft впроваджує оновлення в інших напрямах. Наприклад, GitHub Copilot отримав доступ до GPT-5 того ж дня, коли OpenAI його випустила. То чому ж оновлення .NET runtime із критичним патчем займає стільки часу, особливо при рейтингу 9.9 CVE?

    Офіційна позиція Microsoft

    Команда App Service опублікувала повідомлення, де заявила, що «працює спільно з командою .NET над усуненням проблем, які заважають вчасно постачати оновлення версій .NET runtime, доступних на платформі Windows».

    Також повідомлено про розробку патчу для інфраструктури балансування навантаження, який має пом’якшити уразливість як на Windows-, так і на Linux-екземплярах. Проте оновлень про завершення цього процесу поки що немає.

    Поки що Microsoft радить розробникам використовувати self-contained деплоймент — збирати застосунок із параметром --self-contained і вручну вибирати версію runtime. Наразі це єдиний надійний спосіб убезпечити .NET-застосунки в Azure.

    Як спільнота реагує

    Команда HeroDevs, яка продає платні патчі для застарілих версій .NET (наприклад, .NET 6), випустила на GitHub консольний застосунок для перевірки уразливості вашого runtime.

    Цей тестовий інструмент надсилає спеціальні “request smuggling” запити й перевіряє, чи виникає виняток. На уразливій версії .NET 8 тест не проходить, а на виправленій .NET 10 — успішно виконується.

    Але важливо: цей тест не демонструє реальної експлуатації уразливості. Він лише показує, що новий runtime по-іншому обробляє некоректні запити. Ніякого обходу авторизації не відбувається.

    Спроба зрозуміти суть проблеми

    Імовірно, йдеться про атаку типу HTTP Request Smuggling — коли зловмисник ховає один HTTP-запит (наприклад, DELETE) усередині іншого, легітимного запиту (GET), використовуючи HTTP chunking.

    Приклад:

    • GET /user — запит, доступний будь-якому користувачеві з роллю User.
    • DELETE /user — запит, який вимагає роль Admin.

    Якщо ці запити об’єднані в один, сервер може розділити їх і обробити окремо. Зазвичай Kestrel (вебсервер .NET) видає виняток BadHttpRequestException, що безпечно.

    Але якщо ви винесли перевірку авторизації за межі застосунку — наприклад, у WAF, API Gateway або зовнішній проксі, — цей зовнішній компонент може не побачити прихований запит DELETE. У результаті ваш застосунок у .NET прийме його як дійсний і виконає, вважаючи, що він уже авторизований.

    Отже:

    • Застосунки з зовнішньою авторизацією можуть бути вразливими.
    • Застосунки з вбудованою авторизацією у .NET-коді — найімовірніше, у безпеці.
    • WAF, якщо правильно налаштований, повинен блокувати такі запити.

    Проблема не лише технічна, а й комунікаційна

    Найбільша проблема тут — не стільки сама уразливість, скільки відсутність прозорого спілкування.

    «Баррі, будь ласка, як керівник безпеки .NET, поясніть детальніше. Напишіть блог, у якому чітко розкажіть, що відбувається і як перевірити, чи наш застосунок у небезпеці.»

    Адже виставивши рейтинг 9.9 без будь-яких інструкцій, Microsoft створила дві ситуації:

    1. Здається, ніби компанія щось приховує.
    2. Або ж — поширює паніку без реальної причини.

    Якби рейтинг був 7 чи 8, більшість розробників просто встановила б оновлення і забула. Але 9.9 звучить тривожно, особливо коли самі сервіси Azure залишаються неоновленими.

    Висновок

    Ця ситуація показує: безпека — це не лише про патчі, а й про довіру та комунікацію.

    Команда безпеки Microsoft для .NET має не просто випускати CVE-звіти, а чітко пояснювати ризики та підтримувати актуальність середовищ Azure.

    Поки що єдиний надійний крок для розробників — збирати застосунки з оновленими runtime вручну та уважно стежити за офіційними оновленнями.

  • Керування списками в Microsoft Copilot Studio

    Керування списками в Microsoft Copilot Studio

    Функція List Management у Microsoft Copilot Studio призначена для роботи з об’єктами даних — їх отримання, зміни та синхронізації з зовнішніми джерелами.

    Що таке керування списками

    Керування списками — це робота з наборами даних (об’єктами). Наприклад, у вас є набір даних, що містить список країн, які здобули золоті, срібні та бронзові медалі на Олімпійських іграх. Якщо у цьому списку три країни, і ви хочете додати ще одну, ви можете зробити це динамічно за допомогою функції керування списками.

    Інший приклад — система обробки заявок або квитків. Якщо ваш застосунок зберігає набір квитків, і користувач створює новий квиток через Copilot Studio, ви можете додати цей запис до внутрішнього списку, а потім синхронізувати оновлений список із вашою бекенд-системою.

    Отже, керування списками дозволяє отримувати, змінювати, додавати чи видаляти елементи зі списку, а також очищати весь список за потреби.

    Налаштування агента для керування списками

    Щоб продемонструвати цей процес, створюється простий агент у Copilot Studio (доступний за адресою copilotstudio.microsoft.com). Цей агент не має попередньо заданих інструкцій — це базовий приклад для тестування.

    У розділі Topics створюється нова тема, наприклад List Management.
    Задається тригер — тема запускається, коли користувач вводить слово list.

    Далі перейдіть у Variable Management → List Management. Тут доступні такі дії:

    • Modify the list — змінити вміст списку;

    • Skip to item in the list — перейти до певного елемента;

    • End loop — завершити цикл;

    • Loop through list — перебір елементів у списку.

    Зосередимось на Modify list, яка дозволяє виконувати операції безпосередньо зі списками даних.

    Робота зі змінними та JSON

    1. Створення змінної.
      У Variable Management створіть змінну (наприклад, var1) і вставте JSON-дані — це буде ваш набір даних (наприклад, список країн і кількість здобутих медалей).

    2. Парсинг JSON.
      JSON потрібно розібрати, щоб Copilot Studio розпізнала структуру даних. Виберіть Parse value, задайте тип даних, вставте зразок JSON, і система автоматично визначить схему.

    3. Створення другої змінної.
      Після розбору створіть ще одну змінну (наприклад, var2), яка тепер представляє таблицю записів (records).

    Приклади дій зі списками

    Отримання першого елемента

    У List Management виберіть Modify list, потім дію Take first item.
    Збережіть результат у змінній var3, яка представляє один запис (record).

    Потім можна надіслати повідомлення з вмістом var3.country, щоб відобразити назву першої країни у списку.
    Наприклад, якщо перший запис — United States, саме це значення і буде показано.

    Отримання останнього елемента

    Щоб отримати останній запис, виберіть Take last item, збережіть результат у var3 і запустіть тему знову.
    Copilot Studio покаже країну, яка знаходиться в кінці списку (наприклад, Netherlands).

    Додавання та видалення елементів

    Додавання

    Під час вибору дії Add item потрібно вказати, який саме запис додати. Це може бути новий JSON-об’єкт або змінна, що містить новий запис. Якщо структура правильна, Copilot Studio успішно додасть його до набору даних (var2).

    Видалення

    Дія Remove item дозволяє видалити певний запис зі списку. Ви можете задати, який саме елемент потрібно видалити, вибравши змінну або визначивши умову.

    Очищення списку

    Команда Clear all items видаляє всі елементи зі списку, залишаючи його порожнім. Після виконання цієї дії ваш набір даних буде повністю очищено.

    Висновок

    Функція List Management у Microsoft Copilot Studio надає потужні інструменти для роботи з динамічними наборами даних. Основні дії включають:

    • Add item — додати новий запис;

    • Remove item — видалити наявний запис;

    • Take first item / Take last item — отримати перший або останній елемент;

    • Clear all items — повністю очистити список.

    Ці інструменти дозволяють ефективно керувати динамічними наборами даних безпосередньо в Copilot Studio, спрощуючи автоматизацію та інтеграцію з бекенд-системами.

  • Як використовувати Prompts у Copilot Studio під час створення агента

    Як використовувати Prompts у Copilot Studio під час створення агента

    Платформа Microsoft Copilot Studio надає потужні інструменти для створення, тестування та розгортання інтелектуальних агентів. Один із ключових інструментів — Prompts (підказки). Вони дозволяють застосовувати штучний інтелект до текстів, документів або зображень для аналізу, узагальнення чи перетворення даних. Нижче наведено докладний посібник із використання Prompts у Copilot Studio та їх інтеграції в агентів.

    Початок роботи в Copilot Studio

    Перейдіть на сайт copilotstudio.preview.microsoft.com.
    Якщо у вас уже створено кілька агентів, виберіть одного з них — наприклад, Demo Agent.

    Далі відкрийте розділ Tools (Інструменти).
    Щоб додати новий інструмент, натисніть Add a tool (Додати інструмент) — з’являться такі варіанти: Prompt, REST API, Agent Flow, MCP і Custom Connector.

    У цьому посібнику ми зосередимось на Prompt.

    Створення Prompt

    Prompt можна створити як усередині агента, так і окремо від нього.
    Окремі Prompts можна повторно використовувати в різних агентах, що робить їх гнучкими та зручними.

    1. Перейдіть у Tools → New Tool → Prompt.
    2. В інтерфейсі Prompt задайте його призначення та функції.
    3. Ви можете застосовувати ШІ до текстів, документів або зображень для аналізу, класифікації чи вилучення інформації.

    Для прикладу створіть Prompt із назвою “ABC Prompt” як тимчасовий варіант.

    Налаштування Prompt

    В інтерфейсі Prompt ви можете:

    • Написати інструкцію — що саме має виконувати цей Prompt.
    • Переглядати результати у форматах Text, JSON або Document Preview.
    • Вибрати модель (наприклад, із Azure AI Foundry).
    • Відкрити додаткові налаштування через меню з трьома крапками:
      • Temperature — регулює креативність відповідей;
      • Record retrieval — кількість записів, які потрібно отримати;
      • Include links — додавати посилання у відповідях;
      • Code Interpreter — увімкнути інтерпретатор коду.

    Бібліотека Prompt

    Розділ Prompt Library дозволяє обирати готові шаблони або переглядати категорії, як-от Architecture, Communications, Image Analysis тощо.

    Наприклад:

    • У категорії Architecture є шаблон Extract Information from a Floor Plan — вилучення даних із плану приміщення.
    • У Communications доступний шаблон Pitch Perfection Review.

    Після вибору шаблон автоматично завантажується у ваш робочий простір, де ви можете його змінити або замінити іншим.
    Деякі Prompts містять приклади вхідних даних, наприклад текст або PDF-документ.

    Приклад: додавання підписів до зображень

    Розглянемо приклад створення Prompt для генерації підписів до зображень:

    1. У бібліотеці Prompts знайдіть слово Images.
    2. Виберіть шаблон “Add Captions to Images”.
      Його опис: Створіть людинозрозуміле речення, що описує вміст зображення.
    3. За замовчуванням відкриється приклад зображення — helicopter.jpg.
    4. Натисніть Test (Тест), щоб запустити обробку.
      Приклад результату: “На зображенні показано гелікоптер, що завис біля високої будівлі.”

    Ви можете завантажити власне зображення:

    • Натисніть Image → Upload Image or Document.
    • Виберіть файл (наприклад, Capybara.jpg).
    • Модель (наприклад, GPT-4.1 Mini) проаналізує зображення і поверне опис:
      “На зображенні зображено велику коричневу пухнасту тварину з короткими лапами та масивним тілом.”

    Збережіть Prompt і дайте йому зрозумілу назву, наприклад “Explain Image Caption”.

    Використання Prompt усередині агента

    Після створення Prompt його можна додати до агента:

    1. Натисніть Configure for Use in Agent.
    2. Виберіть потрібного агента — наприклад, Demo Agent.
    3. Prompt буде додано до списку інструментів цього агента.

    Перейдіть у Agents → Demo Agent → Tools, і ви побачите ваш Prompt (наприклад, Explain Image Caption) серед доступних.

    Створення теми (Topic) для роботи з Prompt

    Щоб агент міг взаємодіяти з користувачем через створений Prompt:

    1. Перейдіть у Agents → Demo Agent → Topics.
    2. Створіть нову тему (Create from blank).
    3. Додайте запитання, у якому попросіть користувача завантажити файл:

      “Будь ласка, завантажте файл.”

    4. Вкажіть триггер-фразу, наприклад “image” — при її введенні ця тема активується.
    5. Збережіть завантажений файл як змінну (наприклад, var1).
    6. Додайте вузол-інструмент і підключіть Prompt Explain Image Caption.
    7. Пов’яжіть вхідні дані (завантажене зображення) з Prompt.
    8. Збережіть результат в іншій змінній (наприклад, var2).

    Потім додайте повідомлення, яке покаже результат користувачу, наприклад:

    “Опис вашого зображення: [результат Prompt].”

    Під час тестування — введіть “image”, завантажте файл (наприклад, wombat.jpg) — агент обробить його й поверне відповідь:
    “Зображення показує детальну реалістичну ілюстрацію вомбата з коричневим хутром, що стоїть на чотирьох лапах і трохи повернений праворуч.”

    Використання Prompt у Power Platform

    Однією з головних переваг Prompts є можливість багаторазового використання в різних продуктах Microsoft Power Platform:
    вони доступні в Power Apps, Power Automate і Copilot Studio.

    Power Apps

    1. Перейдіть на make.powerapps.com.
    2. Виберіть потрібне середовище (наприклад, Gishusa USA).
    3. Відкрийте More → Discover All → Prompts.
    4. Закріпіть розділ для швидкого доступу.

    Інтерфейс тут такий самий, як у Copilot Studio — можна створювати або використовувати вже готові Prompts прямо в Power Apps.

    Power Automate

    1. Перейдіть на make.powerautomate.com.
    2. Виберіть середовище.
    3. Перейдіть до More → Discover All → Prompts.
    4. Ви побачите ті самі Prompts, які були створені раніше.

    Це означає, що один Prompt можна створити лише один раз і використовувати в різних продуктах: Power Automate, Copilot Studio і Power Apps.
    Такий підхід забезпечує єдину логіку та економить час.

    Висновок

    Prompts у Copilot Studio — це гнучкий і потужний спосіб інтеграції штучного інтелекту у ваші робочі процеси.
    З їхньою допомогою можна аналізувати тексти, вилучати дані з документів або описувати зображення — усе в єдиному середовищі.

    Створюючи багаторазові Prompts, ви отримуєте інструмент, який можна використовувати в Power Apps, Power Automate та Copilot Studio, що робить ваші AI-рішення ефективнішими, універсальнішими та масштабованими.

  • Детальний огляд .NET AI Template від Microsoft

    Сьогодні ми детально розглянемо .NET AI Template від Microsoft, який був випущений у березні. Цей шаблон містить два типи проєктів — AI Chat Web App та Local MCP Server Console App.

    У цьому матеріалі ми зосередимося на AI Chat Web App: встановимо шаблон, подивимось, що він містить, створимо проєкт у Visual Studio та запустимо його, щоб побачити, як усе працює.

    Встановлення .NET AI Template

    Почнемо з установки шаблону AI.
    Відкрийте термінал і виконайте команду:

    dotnet new install Microsoft.Extensions.AI.Templates

    Ця команда встановлює шаблони локально. Після завершення встановлення ви побачите два нові шаблони:

    • AI Chat Web App

    • Local MCP Server Console App

    Використовувати їх можна у Visual Studio, Visual Studio Code (з установленим C# Dev Kit) або напряму через командний рядок, виконавши:

    dotnet new aichatweb

    або

    dotnet new mcpserver

    щоб створити проєкт безпосередньо у вашій робочій директорії.

    Для сьогоднішньої демонстрації ми скористаємося AI Chat Web App у Visual Studio.

    Створення проєкту у Visual Studio

    Перейдімо до Visual Studio.
    На екрані Create a new project (створення нового проєкту) відкрийте випадаюче меню All project types. Тепер ви побачите нову категорію — AI.

    Виберіть її, і ви знайдете два шаблони:

    • AI Chat Web App

    • Local MCP Server Console App

    Оберіть AI Chat Web App і натисніть Next.
    Задайте ім’я проєкту, наприклад ChatApp1. Вкажіть розташування та натисніть Create.

    Після цього з’явиться можливість обрати постачальника AI-моделі та векторне сховище.

    Доступні постачальники AI-сервісів:

    • Azure OpenAI

    • GitHub Models

    • Alma

    • OpenAI Platform

    У цьому прикладі ми використаємо GitHub Models із локальним векторним сховищем, адже це найпростіший спосіб швидко почати.

    Натисніть Create, і Visual Studio автоматично згенерує проєкт, включаючи інтерфейс на Blazor, папку Data та налаштування сервісів.

    Налаштування GitHub токена

    Далі потрібно додати GitHub токен.
    У файлі README вашого проєкту вказана інструкція:

    "GitHubModelsToken": "your-token"

    Цей токен потрібно вставити у файл secrets.json вашого проєкту.

    Відкрийте secrets.json і додайте свій токен, дотримуючись того ж формату JSON, що наведено у прикладі.

    Огляд структури проєкту

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

    • Папка Pages містить сторінки Blazor, наприклад Chat.razor — головний інтерфейс чату.

    • У папці Services зберігається логіка, що керує процесом спілкування.

    • У папці wwwroot/data є приклади PDF-файлів, які використовуються для завантаження даних і семантичного пошуку.

    Під час запуску застосунок читає ці PDF-файли, створює ембеддинги (векторні представлення) і дозволяє чату відповідати на запитання на основі їхнього змісту.

    Файл Program.cs

    Відкрийте файл Program.cs. У ньому автоматично налаштовані AI-сервіси та векторне сховище.

    • Модель LLM: GPT-4.0 Mini

    • Для ембеддингів використовується Text-embedding-3-small

    • Для зберігання — SQLite

    Усе це генерується автоматично — нічого не потрібно налаштовувати вручну.

    Як працює завантаження даних

    У проєкті є кілька основних класів, що відповідають за обробку даних.

    Клас DataIngestor

    Цей клас читає та обробляє PDF-файли з папки wwwroot/data.
    Він витягує текст, створює ембеддинги за допомогою вибраної моделі та зберігає їх у векторній базі даних SQLite.

    Таким чином ваші документи перетворюються на пошукові векторні дані, які штучний інтелект може розуміти та використовувати пізніше.

    Клас SemanticSearch

    Під час роботи чату цей клас перетворює запит користувача на ембеддинг, порівнює його з векторами документів і отримує найрелевантніші фрагменти інформації.

    Потім результати передаються мовній моделі, яка формує відповідь природною мовою, часто з посиланнями на джерело.

    Разом ці класи дають змогу застосунку відповідати, спираючись на зміст документів, а не генерувати випадкові відповіді.

    Запуск застосунку

    Запустімо застосунок і подивімося, як він працює.

    Після запуску програма автоматично обробить приклади PDF-файлів у wwwroot/data та створить ембеддинги.

    У браузері відкриється чистий інтерфейс чату на Blazor.

    Тепер можна ставити запитання, наприклад:

    «Що входить до набору для виживання?»

    Застосунок:

    1. Обробить запит,

    2. Виконає семантичний пошук у базі векторів,

    3. Згенерує відповідь із зазначенням джерела (файл і сторінка).

    Усе це відбувається автоматично — без додаткових налаштувань.

    Використання власних даних

    Тепер розглянемо, як змусити чат працювати з вашими документами.

    Відкрийте папку wwwroot/data — там є два PDF-файли за замовчуванням.
    Щоб використати власний контент, просто скопіюйте свій PDF у цю папку.

    Наприклад, можна взяти власну статтю про пагінацію в EF Core, зберегти її як PDF і додати до цієї папки.

    Після цього перезапустіть застосунок.
    Клас DataIngestor автоматично знайде новий файл, зчитає його текст, створить ембеддинги та збереже їх у базі даних.

    Тепер, якщо запитати:

    «Який метод пагінації підходить для великих наборів даних?»

    Чат відповість, використовуючи зміст вашої статті, пояснивши, що Keyset Pagination ефективніший за Offset Pagination для великих таблиць, оскільки не пропускає рядки і працює швидше.

    Під відповіддю також буде посилання на файл і сторінку, звідки взято інформацію.

    Розширення можливостей чат-бота

    Тепер, коли застосунок працює, розглянемо, як можна додати нові функції.

    Проєкт побудований на Microsoft.Extensions.AI, що дозволяє легко підключати власні C# функції, які чат-бот може викликати.

    Це означає, що ви можете дати своєму чат-боту додаткові можливості — отримувати дані з API, виконувати дії або обробляти спеціальні запити.

    Приклад: функція GetWeather

    У файлі Chat.razor можна створити нову C# функцію, наприклад:

    string GetWeather(string city) { // Повертає приклад прогнозу погоди return city switch { "London" => "Drizzle", "Paris" => "Sunny", _ => "Cloudy" }; }

    Потім зареєструйте її в методі OnInitialized, оновивши список інструментів у chat options.

    Тепер чат-бот зможе викликати цю функцію при відповідному запиті.

    Якщо запитати:

    «Яка погода в Лондоні?»

    Чат-бот викличе GetWeather і відповість:

    «Погода в Лондоні — мряка.»

    Таким чином, чат-бот може напряму викликати ваш код на C#.
    Далі ви можете підключати реальні API, бази даних або навіть IoT-пристрої.

    Висновок

    Отже, це був повний огляд .NET AI Template у дії.

    Цей шаблон — потужна відправна точка, якщо ви плануєте створити:

    • AI-асистента

    • Бота для документації

    • Або будь-який AI-застосунок на .NET

  • Нова команда .NET run у .NET 10

    Microsoft представила одне з найбільш захоплюючих нововведень у .NET — нову команду dotnet run. Ця функція доступна в .NET і повністю змінює підхід до написання та запуску коду на C#.

    Тепер більше не потрібно створювати повноцінний проєкт, щоб просто протестувати ідею або вивести «Hello World». Усе стало набагато простіше, легше і дружелюбніше для новачків.

    У цій статті ми розберемо, що це за функція, як вона працює і як можна перейти від простого одиночного файлу до повноцінного .NET-проєкту всього за кілька кроків.

    Початок роботи
    Почнемо з повністю порожньої папки у Visual Studio Code — без файлів проєкту, без рішення, просто чистий робочий простір.

    Зверніть увагу: у вас мають бути встановлені .NET 10 та C# Dev Kit для VS Code.

    Створіть новий файл під назвою hello.cs і вставте в нього наступний код:

    Console.WriteLine("Hello from .NET 10! This is a cool feature.");

    Без просторів імен, без класу, без методу Main() — один файл, один рядок, і все працює.

    Запуск файлу
    А ось і магія. Замість створення проєкту просто відкрийте термінал і введіть:

    dotnet run hello.cs

    І програма запуститься! Результат на екрані:

    Hello from .NET 10! This is a cool feature.

    .NET компілює та запускає файл безпосередньо — без додаткового налаштування та без проєкту. Під капотом код збирається в пам’яті та виконується як скрипт.

    Це ідеально для швидких експериментів або одноразових ідей, які потрібно перевірити на льоту.

    Додаємо функціональність: робота з датами
    Тепер зробимо крок далі. Припустимо, ми хочемо вивести дату публікації, наприклад — 3 дні тому.

    Додамо такий код:

    var postedDate = DateTime.UtcNow.AddDays(-3); Console.WriteLine($"Posted date: {postedDate}");

    Після запуску програма виведе повну дату та час, як і очікувалося. Але це не найзручніший варіант для користувача — рядок занадто громіздкий і нечитабельний.

    Виправимо це.

    Використання NuGet-пакетів без проєкту
    Тепер можна використовувати NuGet-пакети навіть без створення проєкту.

    Візьмемо пакет Humanizer, який форматує дати у зручному вигляді — наприклад, замість відмітки часу покаже «3 дні тому».

    На початку файлу додамо:

    #r "nuget: Humanizer, 2.14.1"

    Далі підключимо простір імен:

    using Humanizer;

    Тепер змінимо виведення в консоль:

    var postedDate = DateTime.UtcNow.AddDays(-3); Console.WriteLine($"Posted {postedDate.Humanize()}");

    Запустіть знову:

    dotnet run hello.cs

    При першому запуску може знадобитися трохи часу, щоб завантажити пакет, але потім все виконується миттєво. Тепер результат виглядає так:

    Posted 3 days ago

    Просто, красиво та читабельно — саме те, що потрібно.

    Створення мінімального API в одному файлі
    Тепер підемо ще далі. Що, якщо потрібно створити невеликий API, але без повноцінного проєкту? Це тепер теж можливо.

    Створіть новий файл api.cs і додайте в нього:

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

    Спробуйте запустити:

    dotnet run api.cs

    Ви отримаєте помилку: WebApplication не існує в поточному контексті. Це логічно — ми використовуємо функції мінімального API, але не вказали, що працюємо з Web SDK.

    Підключаємо Web SDK
    Щоб усе запрацювало, додамо на початок файлу рядок:

    #sdk "Microsoft.NET.Sdk.Web"

    Тепер знову запустимо:

    dotnet run api.cs

    І все працює! API запущено і прослуховує за адресою http://localhost:5000.

    Відкрийте Postman або браузер і перейдіть за маршрутом /testapi. Відповідь:

    Hello from .NET 10!

    Мінімальний API повністю працює — і все це в одному файлі.

    Перетворення файлу на повноцінний проєкт
    Якщо файл стає занадто великим — ви додаєте більше ендпоінтів або middleware — можна легко перетворити його на повноцінний проєкт. Достатньо виконати команду:

    dotnet project convert api.cs

    .NET автоматично:

    • створює нову папку проєкту,
    • переносить туди api.cs,
    • генерує файл .csproj,
    • додає всі необхідні SDK та посилання на пакети.

    Приклад створеного .csproj:

    <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> </PropertyGroup> </Project>

    Тепер можна збирати, відновлювати та запускати проєкт як зазвичай.

    Конвертація Hello World у проєкт
    Те ж саме можна зробити з файлом hello.cs:

    dotnet project convert hello.cs

    .NET створить консольний проєкт і автоматично додасть залежності, які використовувалися, включно з Humanizer.

    Приклад .csproj:

    <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Humanizer" Version="2.14.1" /> </ItemGroup> </Project>

    Усе готово до запуску — і жодного ручного налаштування.

    Висновок
    Ми пройшли шлях від одного C#-файлу з кількома рядками коду до:

    • запуску його безпосередньо через dotnet run,
    • використання NuGet-пакетів,
    • створення мінімального API в одному файлі,
    • і конвертації всього в повноцінний проєкт.

    І все це — без ручного налаштування. .NET 10 справді змінює те, як ми починаємо працювати з C#. Чи ви новачок, який створює прототип, чи досвідчений розробник, який пише скрипт, новий процес став чистішим, швидшим і зручнішим. Якщо стаття виявилася корисною — ставте вподобайку та слідкуйте за новими матеріалами про .NET 10, мінімальні API, AI-інтеграцію та інші оновлення екосистеми .NET.

  • Інтеграція перевірок безпеки в CI/CD: базова основа для .NET-проектів

    У сучасному середовищі розробки ігнорування безпеки залежностей — це не просто недбалість, а свідомий шлях до інцидентів. Кожен новий пакет NuGet, який ви додаєте в проєкт, потенційно може містити вразливості.
    Тому автоматизація перевірки залежностей — це не просто «гарна практика», а необхідний мінімум безпеки, без якого неможливо впевнено випускати надійний продукт.

    У цій статті показано, як додати обов’язковий етап перевірки безпеки (security-scan) у файл .gitlab-ci.yml будь-якого .NET-проєкту, використовуючи стандартні інструменти з пакету .NET SDK.

    Додаємо етап Security Scan до .gitlab-ci.yml

    Нижче наведено YAML-фрагмент, який можна безпосередньо включити у ваш CI/CD-конвеєр:

    security-scan:
    stage: security-scan
    image: mcr.microsoft.com/dotnet/sdk:8.0
    before_script:
    - dotnet tool install --global dotnet-outdated-tool
    script:
    # Step 1: Check for known vulnerabilities in packages. This is mandatory.
    - echo "Searching for KNOWN vulnerabilities in packages..."
    - dotnet list package --vulnerable --include-transitive
    
    # Step 2: Check for outdated packages. Important for maintenance and security.
    - echo "Checking for outdated (non-secure) packages..."
    - dotnet-outdated
    allow_failure: true
    only:
    - main
    - develop
    - merge_requests

    Детальний розбір: перша лінія захисту вашого проєкту

    stage: security-scan

    Перевірка безпеки винесена в окремий етап, щоб підкреслити її важливість.
    Це гарантує, що сканування виконується регулярно — зазвичай після етапів збірки та тестування.

    image: mcr.microsoft.com/dotnet/sdk:8.0

    Використання офіційного Docker-образу .NET SDK від Microsoft забезпечує доступ до найновіших CLI-інструментів, необхідних для надійного аналізу та звітності.

    before_script

    Цей блок готує середовище для сканування.

    Команда

    dotnet tool install --global dotnet-outdated-tool

    встановлює утиліту dotnet-outdated-tool.
    Хоча основна перевірка вразливостей виконується вбудованими засобами, цей інструмент допомагає відстежувати застарілі пакети — важлива частина підтримання «гігієни» залежностей.
    Ігнорування оновлень з часом перетворюється на технічний борг і підвищує ризики безпеки.

    script

    Тут виконуються основні команди, що безпосередньо захищають ваш код.

    • Крок 1: Пошук відомих вразливостей
      Команда dotnet list package --vulnerable перевіряє всі залежності (включно з транзитивними) і показує список небезпечних пакетів.

    • Крок 2: Перевірка застарілих пакетів
      Команда dotnet-outdated визначає залежності, які втратили актуальність або можуть містити невиправлені проблеми.

    allow_failure: true

    Цей параметр дозволяє конвеєру продовжувати роботу навіть у разі виявлення проблем.
    Це зручний компроміс на початковому етапі впровадження — розробники отримують звіт, але процес збірки не блокується.
    Втім, якщо ваш проєкт працює з конфіденційними даними або продакшн-системами, варто встановити false, щоб не допустити злиття коду з відомими вразливостями.

    only

    Цей блок визначає, для яких гілок виконується перевірка — main, develop і merge requests.
    Завдяки цьому можна виявити ризики ще до того, як потенційно небезпечний код потрапить до основної гілки.

    Висновок

    Наведена конфігурація — це не «опція» і не «додаткова функція», а базовий стандарт безпеки для будь-якого .NET-проєкту.
    Вона автоматично виконує дві критично важливі задачі:

    1. Виявляє активні загрози — пакети з відомими вразливостями.

    2. Контролює технічний борг — застарілі залежності, які можуть призвести до проблем у майбутньому.

    Пропускаючи цей етап, ви фактично залишаєте двері відчиненими для атак.
    Додайте ці перевірки сьогодні — і завтра ваш проєкт буде набагато безпечнішим.

  • Створення мультиагентного перекладача за допомогою Microsoft Agent Framework

    Сьогодні ми зануримося у щось абсолютно нове та дуже захоплююче для всіх .NET-розробників — це Microsoft Agent Framework. Цей попередній реліз піднімає інтеграцію штучного інтелекту та .NET на абсолютно новий рівень.

    У цьому посібнику ми створимо перекладач, який переводитиме англійський текст на французьку та іспанську, перевірятиме якість перекладів і формуватиме підсумковий звіт — все це за допомогою декількох ІІ-агентів, що працюють спільно.

    Що таке агенти

    Агент — це, по суті, ІІ-робітник, який може думати, приймати рішення та діяти, щоб досягти мети. Уявіть його як цифрового колегу — у нього є конкретне завдання, власна «особистість», і він може використовувати інструменти або API за потреби.

    Згідно з Microsoft, агент — це не просто система запит–відповідь. Він може:

    • розмірковувати та планувати,

    • викликати API,

    • користуватися пам’яттю,

    • співпрацювати з іншими агентами.

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

    Розуміння робочих процесів

    Робочий процес (workflow) визначає, як агенти взаємодіють один з одним та працюють спільно для виконання завдання. Його можна уявити як блок-схему — спочатку переклад, потім перевірка, а потім підсумок.

    Робочі процеси можуть виконуватися послідовно або паралельно, залежно від сценарію. Вони забезпечують структуру та контроль, перетворюючи випадкові відповіді ІІ у надійні, відтворювані процеси.

    Коротко:

    • Агенти приносять інтелект — вони розуміють контекст, розмірковують і генерують результат.

    • Робочі процеси приносять структуру — вони визначають порядок, залежності та розгалуження.

    Коли ви об’єднуєте їх, отримуєте команду взаємодіючих ІІ-агентів, здатних досягати значно більшого, ніж окремі виклики моделі. Наприклад, один агент може перекладати текст, інший — перевіряти його, а третій — підводити підсумки. Все це координується визначеним вами робочим процесом.

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

    Знайомство з Microsoft Agent Framework

    Тепер поговоримо про зірку сьогоднішнього відео — Microsoft Agent Framework.

    Це новий SDK з відкритим кодом від Microsoft, поки що в попередній версії, який об’єднує агентів, робочі процеси, інструменти та пам’ять в єдину платформу для розробників .NET та Python.

    Він базується на ідеях Semantic Kernel та Autogen, але був перероблений, щоб зробити створення мультиагентних систем простим та масштабованим.

    За допомогою цього фреймворку ви можете:

    • легко створювати агентів,

    • з’єднувати їх через типобезпечні робочі процеси,

    • інтегрувати Azure OpenAI або локальні моделі,

    • виконувати кроки паралельно або з участю людини (human checkpoints).

    Підготовка проекту

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

    1. French Translator Agent — переклад англійського на французьку;

    2. Spanish Translator Agent — переклад англійського на іспанську;

    3. Quality Reviewer Agent — перевірка обох перекладів на точність та тон;

    4. Summary Agent — об’єднує результати в підсумковий звіт.

    Це простий приклад, але він чітко демонструє, як кілька агентів можуть співпрацювати.

    Я вже створив консольний додаток .NET 9. Спочатку очищу файл Program.cs.

    Встановлення необхідних пакетів

    Далі встановимо пакети Microsoft Agent Framework.

    Відкрийте NuGet Package Manager та знайдіть наступні бібліотеки:

    1. Microsoft.Agents.AI — встановіть цей пакет.

    2. Microsoft.Agents.AI.Workflows — допомагає будувати та зв’язувати агентів через робочі процеси.

    3. Microsoft.Extensions.AI.OpenAI — дозволяє інтегрувати моделі OpenAI або розміщені на GitHub.

    Після встановлення всі вони з’являться у розділі Dependencies вашого проекту. Тепер ми готові реалізовувати агентів і робочий процес.

    Додавання клієнта чату

    Клієнт чату дозволяє агентам взаємодіяти з моделлю ІІ.

    У нашому випадку використовується модель GitHub — GPT-4.0 Mini, легка, але потужна, ідеально підходить для демонстрацій. Щоб отримати доступ, потрібен GitHub API key.

    У попередньому відео я показував, як створити такі ключі — обов’язково перегляньте, якщо ще не зробили цього.

    Цей клієнт чату з’єднує наше додаток .NET з моделлю OpenAI на GitHub, щоб ми могли створювати агентів поверх неї.

    Створення French Translator Agent

    Наш перший агент — French Translator.

    Він використовує клієнт чату, створений раніше, і виконує просте завдання — приймає англійський текст та перекладає його на французьку.

    Створюємо екземпляр агента через клас ChatClientAgent і називаємо його French Agent.

    У параметрах вказуємо:

    • Name = “French Agent”

    • Instructions = “Перекладай будь-який наданий текст французькою мовою, зберігаючи природність і точність.”

    Готово — перший агент налаштований.

    Створення Spanish Translator Agent

    Щоб не писати все заново, скопіюйте код French Agent і внесіть кілька змін:

    • Перейменуйте змінну в SpanishAgent;

    • Встановіть ім’я “Spanish Agent”;

    • Змініть інструкції: “Ти — перекладач, який перекладає текст іспанською мовою.”

    Тепер у нас є два агенти:

    • один для французької,

    • інший для іспанської.

    Створення Quality Reviewer Agent

    Далі копіюємо код Spanish Agent і адаптуємо його для Quality Reviewer Agent.

    Перейменовуємо змінну в QualityReviewerAgent та встановлюємо ім’я “Quality Reviewer Agent”.

    Щоб зробити код чистішим, створюємо окрему рядкову змінну з інструкціями:
    string qualityReviewerAgentInstructions = "...";

    Цей агент буде перевіряти переклади та надавати оцінку якості за простою рейтинговою системою.

    Створення Summary Agent

    Тепер створюємо Summary Agent аналогічно.

    Копіюємо код Quality Reviewer Agent і вносимо зміни:

    • Перейменовуємо змінну в SummaryAgent;

    • Ім’я — “Summary Agent”.

    Створюємо новий рядок summaryAgentInstructions та прописуємо призначення:

    “Об’єднай усі рецензії перекладів в один підсумковий звіт.”

    Ось і все — Summary Agent готовий.

    Побудова робочого процесу

    Тепер потрібно зв’язати всіх чотирьох агентів в один процес.

    Створюємо новий AI-агент WorkflowAgent за допомогою класу AgentWorkflowBuilder і викликаємо метод BuildSequential.

    Це означає, що агенти виконуватимуться по черзі:

    1. French Translator

    2. Spanish Translator

    3. Quality Reviewer

    4. Summary Agent

    Наприкінці викликаємо .AsAgentAsync(), щоб об’єднати всю ланцюжок у одного агента, з яким можна взаємодіяти безпосередньо.

    У фреймворку результат одного агента автоматично передається наступному — створюється єдиний конвеєр взаємодії.

    Запуск робочого процесу

    Тепер додамо введення тексту від користувача для тесту.

    Просимо користувача ввести англійське речення і передаємо його агенту через workflowAgent.Run(userInput).

    Текст пройде весь конвеєр:

    1. French Translator

    2. Spanish Translator

    3. Reviewer

    4. Summary Agent

    Кожен етап обробляє результат і передає його далі.

    Для наочного виводу:

    • ім’я агента виводимо жовтим,

    • результат роботи — зеленим.

    Запускаємо додаток.

    У консолі з’явиться запит на введення. Введіть, наприклад, “Hello world” та натисніть Enter.

    Ви побачите:

    • French Agent переклав фразу французькою;

    • Spanish Agent — іспанською;

    • Quality Reviewer Agent перевірив обидва переклади на тон, граматику та точність;

    • Summary Agent створив підсумковий звіт про якість перекладу.

    Імена агентів відображаються жовтим, а їх відповіді — зеленим, що допомагає наочно відстежити послідовність кроків.

    Спробуйте ввести ще кілька речень — ви побачите, як кожен агент виконує свою роль крок за кроком, а весь процес працює автоматично.

    Висновок

    Ми щойно створили повноцінний багатомовний конвеєр перекладу з використанням Microsoft Agent Framework.

    Ось що ми зробили:

    • Створили чотири агенти — French Translator, Spanish Translator, Quality Reviewer та Summary Agent;

    • Об’єднали їх у послідовний робочий процес;

    • Спостерігали, як вони спільно виконують завдання від перекладу до підсумкового звіту.

    Кожен агент відповідав за свою частину роботи, а фреймворк координував всю роботу — від перекладу до перевірки та підсумку.

    Цей приклад демонструє, як легко можна спроектувати структуровані, взаємодіючі ІІ-системи прямо в .NET.

    Ви можете розширити цей робочий процес:

    • додати нові мови,

    • створити додаткові етапи перевірки,

    • інтегрувати зовнішні API для більш глибокого аналізу або покращеного перекладу.

  • Глобальні фільтри запитів у Entity Framework Core 10

    У цьому посібнику ми детально розберемо одну з найкорисніших функцій Entity Framework Core (EF Core) — глобальні фільтри запитів (Global Query Filters).

    Якщо вам коли-небудь доводилося писати однакову умову WHERE у кожному запиті, ви знаєте, як легко забути додати її хоча б один раз — і це може призвести до помилки або навіть випадкового розкриття конфіденційних даних. Глобальні фільтри запитів вирішують цю проблему, автоматично застосовуючи визначені умови до всіх запитів у застосунку.

    У цій статті ми розберемо, що таке глобальні фільтри, коли їх варто використовувати, як їх реалізувати та які покращення з’явилися в EF Core 10 завдяки появі іменованих фільтрів (Named Filters). Також ми створимо практичний приклад реалізації на .NET 10 із використанням SQLite.

    Що таке глобальні фільтри запитів

    Простіше кажучи, глобальний фільтр запиту — це умова, яку EF Core автоматично застосовує до всіх запитів для певної сутності. Це можна вважати постійною умовою WHERE, визначеною один раз у моделі та застосовуваною EF Core до кожної вибірки.

    Це особливо зручно, коли потрібно, щоб певні правила діяли завжди. Найпоширеніші приклади:

    • М’яке видалення (soft delete) — приховування записів, позначених як видалені.
    • Багатоорендність (multi-tenancy) — ізоляція даних для різних клієнтів (тенантів).
    • Архівація — збереження старих записів без їх відображення у звичайних запитах.

    Практичні приклади

    1. М’яке видалення (Soft Delete)

    Замість фізичного видалення рядків із бази можна позначати їх як видалені, встановлюючи прапорець IsDeleted = true. Глобальні фільтри автоматично виключають такі записи з усіх запитів.

    2. Багатоорендність (Multi-Tenancy)

    У SaaS-застосунках, де кілька компаній користуються однією базою даних, глобальний фільтр гарантує, що кожен клієнт бачить лише свої дані — без потреби вручну додавати фільтр у кожен запит.

    3. Архівація

    Деякі дані потрібно зберігати для аудиту чи звітності, але не відображати під час щоденних операцій. Глобальний фільтр дозволяє приховувати такі записи, зберігаючи можливість їх отримання при потребі.

    Реалізація глобальних фільтрів у .NET 10

    Розглянемо, як реалізувати м’яке видалення за допомогою глобальних фільтрів EF Core у новому проєкті .NET 10 Web API.

    Крок 1: Налаштування проєкту

    Створюємо новий проєкт і встановлюємо пакети EF Core:

    • Microsoft.EntityFrameworkCore
    • Microsoft.EntityFrameworkCore.Sqlite
    • Microsoft.EntityFrameworkCore.Tools

    У цьому прикладі використовується база даних SQLite, яка дозволяє EF Core працювати з локальним файлом бази.

    Крок 2: Створення сутності

    У папці Entities створюємо клас Blog:

    public sealed class Blog
    {
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public bool IsDeleted { get; set; }
    }/pre>
    
    Прапорець IsDeleted використовується для позначення записів як видалених без фізичного видалення з бази.

    Крок 3: Налаштування DbContext

    У папці Data створюємо клас ApplicationDbContext, що успадковує DbContext. Додаємо властивість DbSet<Blog> і перевизначаємо метод OnModelCreating:
    modelBuilder.Entity<Blog>()
    .HasQueryFilter(b => !b.IsDeleted);

    Тепер EF Core автоматично виключатиме м’яко видалені записи з усіх запитів до таблиці Blogs.

    Крок 4: Налаштування API-ендпоїнтів

    Створюємо кілька методів API:

    • GET /api/blogs — повертає всі блоги (крім видалених).
    • GET /api/blogs/all — повертає всі блоги, включно з видаленими (.IgnoreQueryFilters()).
    • GET /api/blogs/{id} — отримати блог за ID.
    • POST /api/blogs — створює новий блог.
    • DELETE /api/blogs/{id} — виконує м’яке видалення.

    Крок 5: Підключення SQLite і DI

    Додаємо рядок підключення у appsettings.json:

    "ConnectionStrings": {
    "DefaultConnection": "Data Source=Data/AppDb.db"
    }

    Реєструємо контекст у Program.cs:

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));

    Крок 6: Створення міграцій

    У консолі диспетчера пакетів виконуємо:

    Add-Migration Initial
    Update-Database

    Буде створено базу даних SQLite і таблицю Blogs з полями Id, Name та IsDeleted.

    Тестування API

    Перевіряємо роботу через Postman або .http файл:

    • GET /api/blogs → порожній масив.
    • POST /api/blogs → створює блог.
    • GET /api/blogs → показує створений блог.
    • GET /api/blogs/all → ті ж дані (видалених ще немає).

    Реалізація м’якого видалення

    Змінюємо метод Delete, щоб він не видаляв записи фізично.

    Перевизначаємо метод SaveChangesAsync:

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
    foreach (var entry in ChangeTracker.Entries<Blog>().Where(e => e.State == EntityState.Deleted))
    {
    entry.State = EntityState.Modified;
    entry.Entity.IsDeleted = true;
    }
    return base.SaveChangesAsync(cancellationToken);
    }
    Тепер при видаленні запис лише позначається як видалений.

    Покращення в EF Core 10: Іменовані фільтри

    До версії EF Core 10 були обмеження:

    • Лише один фільтр на сутність.
    • .IgnoreQueryFilters() вимикав усі фільтри одразу.

    Через це не можна було, наприклад, вимкнути фільтр м’якого видалення, зберігши фільтр ізоляції орендаря.

    Іменовані фільтри вирішують цю проблему.

    Тепер можна:

    • Визначати кілька фільтрів для однієї сутності.
    • Вимикати лише потрібний фільтр.

    Приклад:

    modelBuilder.Entity<Blog>()
    .HasQueryFilter("SoftDeleteFilter", b => !b.IsDeleted);

    Щоб вимкнути лише цей фільтр:

    context.Blogs.IgnoreQueryFilters("SoftDeleteFilter");

    Використання констант для імен фільтрів

    Щоб уникнути помилок і підвищити читабельність, створіть статичний клас із константами:

    public static class BlogFilters
    {
    public const string SoftDeleteFilter = "SoftDeleteFilter";
    }

    Тепер можна звертатися до фільтра так:

    .IgnoreQueryFilters(BlogFilters.SoftDeleteFilter);

    Фінальне тестування

    Після додавання іменованих фільтрів:

    • GET /api/blogs → показує лише активні блоги.
    • POST /api/blogs → створює новий блог.
    • GET /api/blogs/all → показує всі блоги, включно з видаленими.

    Висновок

    Глобальні фільтри запитів — це потужний інструмент EF Core, який допомагає автоматизувати логіку вибірки даних і підвищує безпеку застосунку.

    У цьому посібнику ми розібрали:

    • Що таке глобальні фільтри запитів.
    • Як реалізувати м’яке видалення.
    • Які покращення з’явилися в EF Core 10 з іменованими фільтрами.

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