Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
Зачем при изменении сборки менять её ве…

Зачем при изменении сборки менять её версию или как сломать Visual Studio одной командой

23 Мар 2023

При выпуске нового релиза сборки её версию обычно меняют. Это особенно актуально, если разрабатывается библиотека, от которой зависят другие проекты. Но что, если этого не делать? Предлагаю вашему вниманию небольшую историю о проблемах с библиотеками от Microsoft.

1039_SameMSBuildVersionIssues_ru/image1.png

Microsoft.Build 15.1

Я активно участвую в разработке C# анализатора PVS-Studio. Помимо прочего, при работе он использует сборки 'Microsoft.Build.dll', 'Microsoft.Build.Framework.dll' и т. д. Эти библиотеки помогают получать различную информацию из проектного файла, что позволяет выполнять более глубокий анализ.

В какой-то момент разработчики из Microsoft решили, что версией всех подобных сборок всегда будет 15.1. Неважно, меняется ли публичный интерфейс, появляются ли новые типы, меняются ли старые — версия всегда одна и та же. У соответствующих NuGet-пакетов версии меняются, а вот у сборок — нет. На вопрос "почему так?" мне ответил maintainer репозитория msbuild:

This is intentional, and allows API client applications to work with multiple versions of MSBuild.

Ну вроде бы и ладно — это их дело, и никому такой подход не мешает.

Или мешает?

Der Typ "Microsoft.Build.Framework.Traits" konnte nicht geladen werden

Примерно с таким незамысловатым сообщением о падении анализатора к нам обратился клиент. Мы обратились к переводчику и узнали, что сообщение говорит об отсутствии необходимого типа Microsoft.Build.Framework.Traits в одной из наших зависимостей — 'Microsoft.Build.Framework.dll'.

Очевидно, у нас это не воспроизводилось. Нужная сборка всегда устанавливается в папку с исполняемым файлом анализатора, и нужный тип в этой сборке присутствует. В чём же дело?

Не так давно мы как раз обновляли все 'Microsoft.Build.*' зависимости ради поддержки анализа проектов под .NET 7. Взглянув на предыдущие версии анализатора, мы увидели, что в используемой им библиотеке 'Microsoft.Build.Framework.dll' действительно нет нужного типа. Возможно, у клиента как-то некорректно обновился анализатор?

Ничего подобного! По нашей просьбе клиент скинул нам нужный dll-файл, и он оказался вполне корректным — нужный тип там присутствовал. Следующим шагом мы скинули пользователю специальную версию анализатора, которая бы логировала пути, по которым на этапе исполнения подгружаются сборки. И оказалось, что на этапе выполнения подгружалась не библиотека, которая лежала рядом с исполняемым файлом, а её 'аналог' из глобального кеша сборок (global assembly cache, GAC).

Тут-то пазл и собрался!

Итак, имеем:

  • анализатор зависит от нового выпуска сборки Microsoft.Build.Framework 15.1;
  • в GAC лежит старый выпуск этой сборки, но её версия тоже 15.1;
  • на этапе выполнения анализатор просит у среды сборку Microsoft.Build.Framework версии 15.1;
  • CLR великодушно предоставляет ему сборку "нужной" версии из GAC, игнорируя ту, что лежит рядом с exe-файлом;
  • в итоге загружена старая сборка, и при обращении к ней оказывается, что там не хватает Microsoft.Build.Framework.Traits.

Проверить данную гипотезу оказалось легко: достаточно было просто добавить в GAC сборку старого выпуска, и падение воспроизвелось. Но что было ещё интереснее — перестала работать Visual Studio 2022. При открытии появляется весёлое сообщение про то, что всё плохо:

1039_SameMSBuildVersionIssues_ru/image2.png

Как серьёзный и опытный программист, я решил его проигнорировать и просто нажал "да". Сообщение пропало, ну и хорошо. Затем я открыл простейший консольный проект и обнаружил его в печальном состоянии:

1039_SameMSBuildVersionIssues_ru/image3.png

Ну опять же, я человек простой — вижу "unloaded", значит нажимаю "Reload":

1039_SameMSBuildVersionIssues_ru/image4.png

И тут же получаю знакомое сообщение (хотя уже не на немецком):

1039_SameMSBuildVersionIssues_ru/image5.png

Да-да, это то же самое исключение, что возникало у нашего клиента.

Воспроизводится это всё легко:

  • скачиваем пакет Microsoft.Build.Framework 17.0;
  • находим в нём сборку для net472;
  • добавляем её в GAC одним из описанных способов (например, через команду gacutil);
  • поздравляю, вы сломали себе Visual Studio 2022, а в частности — используемый ей MSBuild.

Конечно, у нашего клиента не было цели сломать себе Visual Studio 2022. У него её попросту не было, а потому и заметить её падения он не мог. Вместо этого весь удар на себя принял анализатор, завязанный на новые MSBuild-библиотеки и потому таскающий их с собой.

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

Сначала я писал на эту тему в Twitter и на Stack Overflow, но никакой реакции не получил. Куда более действенным оказалось создание issue в репозитории MSBuild.

В этом issue сам maintainer MSBuild, Rainer Sigwald, уделил моим вопросам немного времени, за что ему большое спасибо. Если обобщить, то он сказал мне 2 вещи:

  • версии у сборок одинаковые специально, потому что для некоторых целей это удобно;
  • вы не должны устанавливать сборки Microsoft.Build.* в GAC.

Никакой возможности обойти GAC при подгрузке сборок на этапе исполнения найти не удалось :(.

Что в итоге

Во-первых, повторю — не стоит добавлять сборки Microsoft.Build.* версии 15.1 в GAC, так как это может сломать MSBuild (ну и что не менее важно — это может сломать PVS-Studio).

Во-вторых, по возможности лучше всё-таки обновлять версию сборки, если в неё вносятся изменения. Таким образом можно уберечь своих пользователей от потенциальных проблем, подобных описанным в статье.

В-третьих, если вы ищете ошибки с помощью PVS-Studio и столкнулись с подобной проблемой, то уже знаете, в чём дело и как быть.

А у меня на этом всё, желаю удачи!

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам