Введение
В прошлом посте мы разобрали агрегатор для независимых плагинов. Теперь — как собирать их под все версии Revit (2019–2027) без копипасты проектов.
Особенно больно нам становится при переходе с .NET 4.8 (Revit 2024) на .NET 8 (Revit 2025). Решение — Directory.Build.props.
Что такое Directory.Build.props🔧
Файл, который MSBuild автоматически подхватывает для всех проектов. В него выносим:
- Конфигурации (R2019…R2027)
- TargetFramework под каждую версию
- OutputPath и константы для #if REVIT_2025
- Общие свойства: UseWPF, PlatformTarget=x64
Результат: .csproj остаётся чистым, а версионность управляется в одном месте.
Настройка и разбор Directory.Build.props ⚙️
Создайте файл Directory.Build.props в корне решения:
Давайте разберем, что тут написано.
Вот тут мы указываем, какие конфигурации у нас будут присутствовать для каждого проекта. То есть, тут мы задали, что любой проект будет обладать конфигурациями R2024, R2025 и R2026 (естественно, для полноценной разработки тут нужно дописать R2019-R2023, так же через точку с запятой)
Вот тут происходит магия выбора фреймворка. Тут я указываю, что когда выбрана конфигурация R2024 (первая строка), то в качестве фреймворка я выбираю net48 (это .NET Framework 4.8). И, как несложно догадаться, для R2025 и R2026 мы вместо net48 указываем net8.0-windows.
Вот здесь мы задаем выходной путь (куда будет по итогу собираться/билдиться) нашему проекту и определяем константы для условной компиляции.
Как можно заметить, выходной путь задан через конфигурацию. Это значит, если происходит билд версии R2021, то результат будет расположен по пути bin/R2021. То же самое касается любой другой версии.
Условная компиляция позволяет нам адаптировать наш проект под любую версию Revit. Давайте разберем на примере. В старых версиях Revit (2019-2021) единицы измерения управлялись через Enum под названием DisplayUnitType. Начиная с Revit 2022 этот Enum был заменен на статический класс под названием UnitTypeId. И как нам, не переписывая проект, сделать так, чтобы при выборе старой (R2019-R2021) конфигурации , мы работали с DisplayUnitType, а при выборе новой (любой другой) конфигурации — с UnitTypeId? Именно тут нам на помощь приходят DefineConstants. Мы объявили, что для условной компиляции мы можем использовать:
- DEBUG — по умолчанию было, можно убрать за ненадобностью
- $(Configuration) — конфигурация проекта
- REVIT_$(RevitVersion) — Версия Revit
Это значит, что в коде я могу написать следующее:
Тут указано, что если выбрана версия R2019 || R2020 || R2021, то я буду делать entity.Set при помощи DisplayUnitType:
И теперь вишенка на торте. Как писать код, не имея нужной версии Revit? Я хочу написать плагин или проверить совместимость своего плагина с версией Revit 2026, которой нет на компьютере. И делать я это буду при помощи NuGet-пакета, который так же уже указан в Directory.Build.props:
Как вы можете заметить, версия пакета управляется через RevitVersion. То есть, при смене конфигурации вы автоматически будете переключаться между .dll-файлами Revit, при этом, все эти файлы содержатся внутри пакета, поэтому вам даже Revit не нужен для того, чтобы писать плагины под него😁
Настройка файла .csproj
Что же до файла .csproj — в нем остается только необходимый ему минимум. Вы можете прямо сейчас открыть свой .csproj файл и посмотреть, какой он огромный. А вот так они выглядят у меня:
По сути, мне здесь остается только сказать, что это Library (библиотека классов) и все. Ссылки добавляются в ходе написания кода, и бывают проекты, которым они не нужны. Тогда их .csproj файл вообще состоит только из этих 5 строк:
Настройка IDE
После предыдущих шагов вам осталось только создать конфигурации решения в IDE.
Делается это через Build → Configuration Manager → <New…>, там вы создаете конфигурации под все версии Revit (R2019 → R2026).
В целом, это все. Вне зависимости от того, используете ли вы агрегатор из прошлого поста, или не используете, вы можете повторить данный алгоритм на своем решении и получить тот самый, ожидаемый результат. Но вот простая диаграмма, которая еще раз закрепит понимание, как работает Directory.Build.props с проектом-агрегатором:
Он просто передает настройки, определенные в нем, всем проектам, которые есть в решении MainApp.
Готовый файл 📦
Полный Directory.Build.props с поддержкой 2019–2027 — в моем телеграм-канале. Просто положите его в корень и создайте конфигурации решения, и будет вам счастье.
--
Мучились ли вы с версиями фреймворка? Как делали мультиверсионность? Как работали с .dll-ками Revit? Остались вопросы? Все это можно рассказать в комментариях!