Завершение поддержки .NET 8: как найти все зависимые приложения и подготовить обновление
Содержание 13 разделов
Дедлайн один на всех: 10 ноября 2026 года, и он касается не только .NET 8
Поддержка .NET 8 и .NET 9 заканчивается в один день — 10 ноября 2026 года [1][2]. После этой даты Microsoft перестаёт выпускать патчи безопасности и техническую поддержку для обеих веток, а приложения продолжают работать, но без защиты от новых уязвимостей [1][3]. Чтобы подготовиться, нужно: инвентаризировать серверы и SDK, проверить TargetFramework во всех проектах, найти self-contained сборки и Docker-образы с зафиксированной версией, прогнать dotnet list package на устаревшие и уязвимые пакеты, обновиться поэтапно и настроить мониторинг версии runtime после релиза.
Почему на этот раз нельзя просто «подождать ещё немного»
У .NET 8 репутация надёжной LTS-версии — три года поддержки, стабильный релиз, на который перешли многие корпоративные системы после .NET 6. Именно поэтому вокруг него возникает соблазн отложить обновление: платформа ещё официально поддерживается, приложения работают, а миграция требует ресурсов команды.
Особенность именно этого перехода в том, что вместе с .NET 8 (LTS) в тот же день, 10 ноября 2026 года, заканчивается поддержка и .NET 9 (STS) [1][2]. Раньше STS-версии жили полтора года и переставали поддерживаться раньше своей LTS-соседки; теперь Microsoft продлила срок поддержки STS-релизов до 24 месяцев, и это привело к тому, что обе ветки — и те, кто выбрал стабильность, и те, кто выбрал свежие фичи — сходятся в одну и ту же дату обновления [4][5]. Это увеличивает спрос на миграцию одновременно у большого числа компаний, а значит — и конкуренцию за время внутренних платформенных команд и подрядчиков.
Материал полезен разработчикам корпоративных приложений, техническим руководителям и внутренним ИТ-службам, которым нужно понять реальный масштаб задачи до того, как дедлайн станет горящим.
Что именно происходит 10 ноября 2026 года
Разберём по пунктам, что означает окончание поддержки на практике.
- Приложения на .NET 8 и .NET 9 не перестают работать в этот день — рантайм не блокируется и не отключается [3].
- Microsoft прекращает выпуск обновлений безопасности и исправлений ошибок для обеих веток [1][3].
- Техническая поддержка через официальные каналы Microsoft для .NET 8/9 больше не предоставляется [3].
- Начиная с одного из будущих обновлений Visual Studio 2022, компоненты .NET 8 и .NET 9 будут помечены как неподдерживаемые; существующие установки при этом не удаляются автоматически, но пользователей предупреждают об использовании возможности инсталлятора «удалить неподдерживаемые компоненты» [4].
- Рекомендуемая целевая версия — .NET 10, LTS-релиз с поддержкой до ноября 2028 года [1][3].
Важно различать два похожих, но разных факта: то, что дата окончания поддержки .NET 8 и .NET 9 официально подтверждена Microsoft — это факт [1][2]; то, каким именно будет коммерческое предложение продлённой поддержки от сторонних вендоров (расширенные патчи после EOL) — это рыночная практика, которая существует, но условия у разных поставщиков разные, и их нужно проверять отдельно, а не воспринимать как продолжение официальной поддержки Microsoft.
Как устроена система поддержки .NET и почему даты именно такие
Microsoft выпускает крупный релиз .NET ежегодно, в ноябре. Чётные версии (.NET 6, 8, 10) — LTS-релизы с поддержкой минимум три года; нечётные (.NET 7, 9, 11) — STS-релизы, сейчас поддерживаемые 24 месяца или 12 месяцев после выхода следующей версии, в зависимости от того, что наступит позже [6][7]. Качество и уровень тестирования у LTS и STS одинаковые — разница только в длительности поддержки [8].
Патчи выходят ежемесячно, во второй вторник месяца («Patch Tuesday»), поэтому даты окончания поддержки почти всегда приходятся на вторник, а не на годовщину релиза [8][5]. Ещё одна деталь, которую часто упускают: чтобы формально считаться «поддерживаемым», приложение должно работать на последней патч-версии своей ветки — то есть само по себе нахождение в пределах трёх лет LTS не гарантирует поддержки, если давно не обновлялись минорные патчи [3].
Отдельно стоит следить за версией ASP.NET Core и Entity Framework Core: они поставляются как часть релиза .NET и наследуют его жизненный цикл, то есть заканчивают поддержку в ту же дату, что и сам рантайм [9].
Что нужно учитывать в российском контексте
Международная техническая часть — сроки и правила поддержки — везде одинаковая, но при планировании обновления в российской компании стоит дополнительно проверить несколько вещей.
Доступность внешних реестров. Инструменты вроде NuGet.org, Docker Hub и Microsoft Container Registry (mcr.microsoft.com) используются практически на каждом шаге — от восстановления пакетов до вытягивания базовых образов в CI/CD. Прежде чем планировать даты обновления, стоит заранее проверить, что раннеры CI/CD и рабочие машины разработчиков имеют стабильный доступ к этим источникам из корпоративной сети, либо настроить внутренние зеркала/прокси-фиды NuGet и приватный container registry, чтобы обновление не встало из-за сетевых ограничений в самый неподходящий момент.
Импортозамещение и КИИ. Если приложение относится к объектам критической информационной инфраструктуры или используется в органе государственной власти, вопрос обновления .NET может пересекаться с более широким требованием об использовании отечественного ПО и включённых в реестр Минцифры продуктов. Это отдельная юридическая и архитектурная тема, которая выходит за рамки чисто технического апгрейда версии рантайма — если она актуальна для вашей организации, её стоит прорабатывать отдельно с профильными специалистами, а не решать «попутно» с обновлением .NET.
Иностранный вендор и поддержка. .NET — платформа с открытым исходным кодом, но официальная поддержка и патчи выпускаются американской компанией. Для организаций, которые обязаны учитывать риски зависимости от иностранного ПО, это дополнительный аргумент в пользу заблаговременного планирования, а не работы «в последний момент, когда как раз может понадобиться срочная связь с вендором».
Подтверждённых данных о специальных отраслевых требованиях именно к версии .NET (в отличие от общих требований к используемому стеку) в открытых источниках найти не удалось — при необходимости этот вопрос стоит уточнять по своей отрасли отдельно.
Как найти все приложения, которые зависят от .NET 8
Первая практическая проблема — понять реальный периметр: сколько сервисов, где они развёрнуты и на какой именно версии .NET/ASP.NET Core работают. В организациях с десятками микросервисов и историческими решениями «какой-то Иван три года назад поднял на .NET 8» этот шаг часто оказывается самым трудоёмким.
Проверка установленных SDK и runtime на серверах
На каждой машине, где запускаются или собираются .NET-приложения, можно посмотреть, что установлено:
dotnet --list-sdks dotnet --list-runtimes dotnet --info
Команда dotnet --list-runtimes покажет все установленные рантаймы (Microsoft.NETCore.App, Microsoft.AspNetCore.App, Microsoft.WindowsDesktop.App) с версиями, а dotnet --list-sdks — установленные SDK [3]. Команда dotnet --info объединяет обе выдачи и добавляет информацию об ОС и RID [10][3].
Более полезный для аудита инструмент — dotnet sdk check: он не просто перечисляет версии, а сразу помечает, какие из установленных SDK и рантаймов уже вне поддержки, а какие устарели до последнего патча в рамках своей ветки [11]. Это удобно прогонять по всем серверам одним скриптом и сразу получать список машин, требующих внимания.
Если приложений и серверов много, есть смысл собрать эти команды в единый инвентаризационный скрипт (PowerShell/bash), который проходит по списку хостов и складывает результат в таблицу — версия SDK, версия рантайма, статус поддержки, хост.
Проверка TargetFramework в проектах
В файлах .csproj целевая версия задаётся тегом TargetFramework (для проектов, ориентированных на одну версию) или TargetFrameworks (для мультитаргетинга) [12][13]:
<TargetFramework>net8.0</TargetFramework>
или
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
Для одного репозитория проще всего пройтись рекурсивным поиском по всем .csproj/.fsproj файлам и вытащить значение тега — это можно сделать простым скриптом на PowerShell или bash с grep/Select-String, который строит сводную таблицу «проект → целевой фреймворк → путь» [13]. Для множества репозиториев в корпоративном GitHub/GitLab такой обход можно автоматизировать через API системы контроля версий, чтобы не открывать каждый репозиторий вручную.
Отдельно стоит поискать проекты, которые используют устаревший, не-SDK-style формат .csproj с тегом TargetFrameworkVersion — это признак приложений, которые исторически мигрировали с .NET Framework и могут требовать более глубокого анализа перед апгрейдом, чем просто смена номера версии [13].
Как обнаружить self-contained deployments
Self-contained развёртывание — это когда приложение публикуется вместе с самим рантаймом и не зависит от того, что установлено на сервере [14]. Такие приложения не видны через dotnet --list-runtimes на хосте (там будет пусто или другая версия), поэтому их легко пропустить при инвентаризации по серверам — нужно смотреть в сами артефакты публикации.
Признаки self-contained сборки:
- в проекте задан
<SelfContained>true</SelfContained>или указан<RuntimeIdentifier>вместе с--self-containedпри публикации [15][14]; - в папке публикации присутствуют файлы самого рантайма (например,
libcoreclr.so/coreclr.dll), а не только сборки приложения; - используется
<PublishSingleFile>true</PublishSingleFile>— тогда всё упаковано в один exe/бинарник конкретной платформы [15][16].
Важный нюанс, о котором стоит знать при аудите: начиная с .NET 8, для проектов, нацеленных на .NET 8 и новее, указание RuntimeIdentifier больше не подразумевает автоматически self-contained — по умолчанию такие приложения framework-dependent, и SelfContained нужно указывать явно [4]. Это значит, что при переносе логики поиска self-contained-сборок со старых проектов (.NET 6/7) на .NET 8 нельзя полагаться только на наличие RuntimeIdentifier — нужно явно проверять значение SelfContained.
Поскольку single-file и self-contained артефакты всегда специфичны для конкретной ОС и архитектуры, публикуются отдельно под каждую платформу (Linux x64, Windows x64 и так далее) [16] — при инвентаризации стоит проверять не только исходный код, но и то, что реально лежит в папках деплоя на продакшене, включая CI-артефакты прошлых релизов.
Проверка Docker-образов и CI/CD
Официальные образы .NET публикуются в Microsoft Artifact Registry по адресу mcr.microsoft.com с тремя основными семействами: dotnet/sdk (для сборки), dotnet/aspnet (рантайм ASP.NET Core) и dotnet/runtime (базовый рантайм) [17][18]. Версия зашита прямо в тег, например mcr.microsoft.com/dotnet/aspnet:8.0 [17][19].
Практический план проверки:
- Пройтись по всем
Dockerfileв репозиториях и найти строкиFROM mcr.microsoft.com/dotnet/...:8.0*— это прямой признак зависимости от .NET 8 на уровне контейнера. - Проверить CI/CD-пайплайны (GitHub Actions, Azure DevOps, GitLab CI, TeamCity) на явное указание версии SDK — например, шаг установки
.NET SDK 8.0.xв конфигурации workflow. - Проверить реестр образов организации (Docker Registry/Harbor/ACR) на теги с версией 8.0 — это покажет, какие образы реально собираются и деплоятся, а не только что написано в исходниках.
- Учесть, что с .NET 8 Microsoft перестала публиковать «мультиплатформенные» теги для Windows-контейнеров — под Windows нужно использовать теги с явным указанием варианта ОС, например
8.0-nanoserver-ltsc2022или8.0-windowsservercore-ltsc2022[20][21]. Если в компании используются Windows-контейнеры, это отдельная точка, которую нужно перепроверить при обновлении Dockerfile на .NET 10.
Отдельно стоит убедиться, что мультистейдж-сборки, где отдельно указана версия для стадии сборки (sdk) и стадии финального образа (aspnet/runtime), обновляются согласованно — рассинхронизация версий SDK и рантайма в многостадийном Dockerfile — частая причина трудноуловимых ошибок после апгрейда.
Какие NuGet-пакеты могут заблокировать обновление
Перед тем как переключать TargetFramework на net10.0, стоит проверить состояние зависимостей — иначе апгрейд рантайма может упереться не в код приложения, а в чужой пакет.
Встроенная команда dotnet list package поддерживает три полезных режима [22][23]:
dotnet list package --outdated dotnet list package --deprecated dotnet list package --vulnerable --include-transitive
--outdatedпоказывает пакеты, для которых вышли более новые версии [22][24].--deprecatedпоказывает пакеты, помеченные автором или NuGet.org как устаревшие, включая маркер уязвимости прямо в выдаче, если такой пакет ещё и содержит известную уязвимость [25].--vulnerableиспользует данные из GitHub Advisory Database (через NuGet audit sources) и показывает пакеты с известными уязвимостями [23].
Важный практический момент: по умолчанию все три режима проверяют только пакеты верхнего уровня (те, что прямо указаны в проекте), а не всю транзитивную цепочку зависимостей — реальный риск часто скрыт на уровне ниже. Флаг --include-transitive нужно указывать отдельно, чтобы получить полную картину [26][23]. Опции --vulnerable, --deprecated и --outdated при этом нельзя комбинировать друг с другом в одном вызове — команду нужно прогонять по очереди для каждого режима [25][22].
Дополнительно можно включить аудит пакетов прямо при восстановлении зависимостей — на уровне проекта или Directory.Build.props:
<PropertyGroup> <NuGetAudit>true</NuGetAudit> <NuGetAuditMode>all</NuGetAuditMode> </PropertyGroup>
Это заставит сборку автоматически предупреждать о вредных пакетах при каждом dotnet restore, а не только при ручном запуске отчёта [23].
Помимо формальных проверок, стоит обратить внимание на пакеты, которые:
- давно не обновлялись авторами и явно не тестировались на новых версиях .NET — это не значит, что они точно сломаются, но риск нужно закладывать в план;
- содержат нативные компоненты, привязанные к конкретному Runtime Identifier — при смене целевой платформы или self-contained-конфигурации такие пакеты требуют отдельной проверки совместимости RID;
- используются в multi-targeting проектах (
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>) — добавлениеnet10.0в список может потребовать проверки условной компиляции и#if— директив под конкретный TFM.
Практические этапы обновления
Дальше — последовательность действий, которая подходит для большинства организаций с несколькими сервисами на .NET 8; для одного монолитного приложения шаги те же, но проще по масштабу.
- Инвентаризация. Собрать полный список серверов, SDK/рантаймов, репозиториев,
TargetFramework, self-contained сборок и Docker-образов, как описано выше. Без этого шага дальнейшее планирование строится на догадках. - Приоритизация сервисов. Определить порядок обновления — обычно начинают с сервисов без зависимостей от других (библиотек и базовых модулей), чтобы не блокировать команды, которые от них зависят.
- Проверка зависимостей. Прогнать
dotnet list package --outdated/--deprecated/--vulnerable --include-transitiveпо каждому проекту и составить список пакетов, которые нужно обновить до перехода на новый TFM. - Обновление TargetFramework. Сменить
net8.0наnet10.0в файлах проектов; официально этот шаг Microsoft описывает именно как изменение значения свойстваTargetFrameworkв файле проекта [3]. - Просмотр списка breaking changes. Перед массовым обновлением стоит свериться с официальным списком критичных изменений между версиями .NET — большая часть проблем при апгрейде возникает не из-за нового TFM самого по себе, а из-за конкретных поведенческих изменений в рантайме или библиотеках.
- Использование средств автоматизации. Ранее для этого использовался .NET Upgrade Assistant, но Microsoft официально пометила его как устаревший инструмент и рекомендует вместо него агент модернизации GitHub Copilot, встроенный в Visual Studio 2026 и Visual Studio 2022 версии 17.14.16 и выше — он анализирует проект и зависимости, строит пошаговый план миграции и коммитит изменения по шагам, что позволяет проверить или откатить каждое из них [27][28]. Даже с автоматизацией результат нужно тестировать вручную — инструмент ускоряет рутину, но не заменяет ревью.
- Регрессионное тестирование. Прогнать полный набор автоматических тестов (unit, integration, при наличии — end-to-end) на обновлённой версии, обращая внимание не только на упавшие тесты, но и на изменившееся поведение сериализации, дат, культур и API, которые часто меняются между мажорными версиями .NET без явных ошибок компиляции.
- Обновление контейнеров и CI/CD. Обновить теги базовых образов в Dockerfile, версии SDK в пайплайнах и убедиться, что мультистейдж-сборки используют согласованные версии SDK и рантайма.
- Поэтапный роллаут микросервисов. Обновлять сервисы по одному или небольшими группами, а не «всё и сразу» — это снижает риск одновременного падения нескольких зависимых друг от друга частей системы и облегчает откат при проблеме.
- Контроль версии runtime после деплоя. После обновления стоит зафиксировать в мониторинге фактическую версию рантайма, с которой работает каждый сервис в проде — например, логировать
Environment.Version/RuntimeInformation.FrameworkDescriptionпри старте приложения или включить эту информацию в health-check эндпоинт, чтобы расхождение между «что задеплоено по документам» и «что реально запущено» не обнаруживалось только во время инцидента.
Ограничения, ошибки и риски
- Иллюзия «оно и так работает». Главная ошибка — путать «приложение продолжает запускаться» с «приложение поддерживается». После 10 ноября 2026 года первое верно, второе — нет [3].
- Self-contained сборки, забытые при инвентаризации. Поскольку они не отражаются в
dotnet --list-runtimesна хосте, именно такие приложения чаще всего выпадают из первого раунда аудита. - Смешение версий SDK и рантайма в мультистейдж Docker-сборках. Обновили
aspnet:10.0в финальной стадии, но забылиsdk:10.0в стадии сборки (или наоборот) — типичная причина неожиданных ошибок совместимости. - Транзитивные зависимости вне поля зрения. Проверка только пакетов верхнего уровня без
--include-transitiveсоздаёт ложное ощущение чистоты дерева зависимостей. - Расчёт на автоматический инструмент без ревью. Даже официально рекомендованный агент модернизации GitHub Copilot формирует план и коммитит изменения пошагово именно для того, чтобы их можно было проверять и откатывать — использование «вслепую» противоречит логике самого инструмента [28].
- Недооценка сетевой зависимости от внешних реестров. Если CI/CD не может стабильно достучаться до NuGet.org, Docker Hub или mcr.microsoft.com, обновление может застопориться не из-за кода, а из-за сетевой конфигурации — это стоит проверить заранее, а не в день релиза.
- Игнорирование сторонних библиотек, которые тестируются медленнее вас. Постепенно библиотека может прекратить тестирование на устаревшей версии, затем перестать публиковать совместимые сборки, и в итоге совместимость с версией, на которой вы остались, будет постепенно расходиться с тем, что реально поддерживают её зависимости — это происходит не одномоментно, а постепенно, и стоит закладывать это как риск даже для «стабильных» пакетов.
Как выбрать решение: готовое обновление своими силами или помощь со стороны
Если у компании один-два сервиса, есть внутренняя DevOps-экспертиза и обновление укладывается в обычный релизный цикл — обновление до .NET 10 вполне можно провести своими силами по шагам выше, дополнительно привлекая ИИ-агенты модернизации для рутинных правок.
Внешняя помощь становится более оправданной, когда:
- сервисов много, они разного возраста, и часть написана без документации или без владельца в команде;
- в парке есть self-contained приложения или Windows-специфичный код (например, старые Windows Forms/WCF-модули), для которых миграция сложнее, чем смена TFM;
- нужно синхронизировать обновление с требованиями безопасности, комплаенса или ограничениями по доступности внешних реестров в инфраструктуре компании;
- команда физически не успевает провести полноценное регрессионное тестирование в доступное до дедлайна время.
Не всегда для этого нужна полноценная разработка — иногда достаточно технического аудита, который покажет реальный объём работ и приоритеты, либо разовой консультации по конкретным блокирующим местам (например, по несовместимому пакету или self-contained-конфигурации).
Как может помочь «Пятый фактор»
Основная сложность обновления платформы редко сводится к одной команде dotnet publish — сложнее собрать полную картину зависимых сервисов, оценить, какие пакеты и интеграции могут не пережить переход, и провести обновление так, чтобы не остановить продакшен. Команда «Пятого фактора» может изучить существующий парк приложений, провести технический аудит зависимостей от .NET 8 и помочь с планированием и реализацией поэтапного обновления — от точечной консультации по проблемным местам до полноценного сопровождения миграции нескольких сервисов.
Чтобы обсудить задачу или получить консультацию, свяжитесь с командой «Пятого фактора» любым удобным способом.
Вывод
10 ноября 2026 года — не абстрактный дедлайн из документации, а конкретная дата, после которой .NET 8 и .NET 9 остаются без патчей безопасности [1][2]. Риск в том, что задача выглядит простой («поменять TargetFramework»), а на практике распадается на десятки скрытых мест: self-contained сборки, забытые Docker-теги, транзитивные пакеты, Windows-контейнеры с устаревшими образами. Инвентаризация до начала миграции — это не бюрократия, а способ не обнаружить забытый сервис уже после того, как поддержка закончилась.
Источники
[1] devblogs.microsoft.com — .NET 8 and .NET 9 will reach End of Support on November 10, 2026 — https://devblogs.microsoft.com/dotnet/dotnet-8-9-end-of-support/
[2] infoworld.com — End of support looms for .NET 8 and .NET 9 — https://www.infoworld.com/article/4191704/end-of-support-looms-for-net-8-and-net-9.html
[3] learn.microsoft.com — Check installed .NET versions on Windows, Linux, and macOS — https://learn.microsoft.com/en-us/dotnet/core/install/how-to-detect-installed-versions
[4] learn.microsoft.com — Breaking change: Runtime-specific apps no longer self-contained — https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/8.0/runtimespecific-app-default
[5] devblogs.microsoft.com — .NET STS releases supported for 24 months — https://devblogs.microsoft.com/dotnet/dotnet-sts-releases-supported-for-24-months/
[6] dotnet.microsoft.com — .NET and .NET Core official support policy — https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core
[7] learn.microsoft.com — Lifecycle FAQ - .NET and .NET Core — https://learn.microsoft.com/en-us/lifecycle/faq/dotnet-core
[8] dotnet.microsoft.com — The official .NET support policy — https://dotnet.microsoft.com/en-us/platform/support/policy
[9] learn.microsoft.com — .NET releases, patches, and support — https://learn.microsoft.com/en-us/dotnet/core/releases-and-support
[10] thecodebuzz.com — How to Check .NET Core version installed SDK and Runtime — https://thecodebuzz.com/get-sdk-and-runtime-version-net-core/
[11] learn.microsoft.com — dotnet sdk check command - .NET CLI — https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sdk-check
[12] learn.microsoft.com — Target Frameworks Reference for NuGet — https://learn.microsoft.com/en-us/nuget/reference/target-frameworks
[13] puresourcecode.com — Scanning .NET Target Frameworks with PowerShell — https://puresourcecode.com/tools/powershell/scanning-net-target-frameworks-with-powershell/
[14] learn.microsoft.com — .NET application publishing overview — https://learn.microsoft.com/en-us/dotnet/core/deploying/
[15] learn.microsoft.com — Create a single file for application deployment - .NET — https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file/overview
[16] github.com — Single-file deployment - dotnet/docs — https://github.com/dotnet/docs/blob/main/docs/core/deploying/single-file/overview.md
[17] mcr.microsoft.com — Microsoft Artifact Registry, dotnet/sdk — https://mcr.microsoft.com/product/dotnet/sdk/about
[18] learn.microsoft.com — Official .NET Docker images — https://learn.microsoft.com/en-us/dotnet/architecture/microservices/net-core-net-framework-containers/official-net-docker-images
[19] deepwiki.com — Docker and Container Images | dotnet/core — https://deepwiki.com/dotnet/core/4.2-docker-and-container-images
[20] github.com — Breaking change: Multi-platform .NET 8 tags no longer support Windows containers (dotnet/dotnet-docker) — https://github.com/dotnet/dotnet-docker/discussions/4549
[21] andrewlock.net — Updates to Docker images in .NET 8 — https://andrewlock.net/exploring-the-dotnet-8-preview-updates-to-docker-images-in-dotnet-8/
[22] learn.microsoft.com — dotnet package list command - .NET CLI — https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-package-list
[23] safeguard.sh — NuGet Vulnerability Scanning (2026): dotnet list package Guide — https://safeguard.sh/resources/blog/nuget-package-vulnerability-scanning
[24] josef.codes — Keeping your nuget packages in check — https://josef.codes/keeping-your-nuget-packages-in-check/
[25] github.com — dotnet list package vulnerable · NuGet/Home Wiki — https://github.com/NuGet/Home/wiki/dotnet-list-package---vulnerable/9926064ebded8575ef351533df774b4e4f2ed9d4
[26] mytechramblings.com — How to easily check on your CI/CD pipelines if your app has a NuGet package with a security vulnerability — https://www.mytechramblings.com/posts/check-if-your-dotnet-app-dependencies-has-a-security-vulnerability-on-you-cicd-pipelines/
[27] learn.microsoft.com — .NET Upgrade Assistant Overview - .NET Core — https://learn.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview
[28] dotnet.microsoft.com — GitHub Copilot app modernization | .NET — https://dotnet.microsoft.com/en-us/platform/upgrade-assistant