К основному содержанию
скилл CX Codex

property-patterns — скилл для Claude Code: свойства MSBuild

Разбирает условия, дефолты и перезаписи в свойствах MSBuild по шаблонам из репозитория MSBuild. Пригодится, когда сборка берёт не то значение или падает на чужой ОС.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add dotnet/skills --skill property-patterns -a claude-code
Открыть на GitHub

Что делает property-patterns

Скилл ведёт агента по каноническим приёмам работы со свойствами MSBuild. Он смотрит в проект и уже существующие общие файлы и ищет конкретные дефекты: незакавыченное условие, дефолт без Condition, затирание DefineConstants, абсолютный путь вместо переносимого, значение, которое перебил поздний импорт.

Внутри SKILL.md с блоками XML на каждый случай. Условные дефолты вида Condition="'$(Prop)' == ''", вложенные группы под общим условием, сцепка списков через точку с запятой ($(DefineConstants);MY_FEATURE), нормализация путей через $([MSBuild]::NormalizePath(...)) и $([System.IO.Path]::IsPathRooted(...)), guard-свойства против двойного импорта, гейтинг поведения по версии через $([MSBuild]::AreFeaturesEnabled('17.10')), разбор порядка вычисления по правилу последней записи.

Есть предупреждение, на котором спотыкаются чаще всего: в .props у проекта с одним таргетом $(TargetFramework) пустой, пока не вычислено тело проекта. Условия по TFM оттуда просто не срабатывают, и это повод перенести группу в .targets. За задачи без дефекта свойства скилл не берётся: выбор файла под таргет или перенос импортов без поломки отданы другому скиллу, directory-build-organization.

Какие задачи решает

  • найти свойство, которое перебивает поздний импорт
  • починить дефолт, который не применяется из-за пустого условия
  • дописать DefineConstants, не потеряв прежние константы
  • убрать из .props жёсткий абсолютный путь
  • перенести условные группы по TFM из .props в .targets

Примеры запросов агенту

  • Почему в проекте Configuration всегда Debug? Проверь условия в Directory.Build.props и поправь дефолты.
  • Условие по TargetFramework в .props не срабатывает — разберись и перенеси группу куда надо.
  • Пройди по свойствам в наших общих файлах и найди, где затирается DefineConstants.

Как установить property-patterns

1Через Skills CLI (Vercel)

npx skills add dotnet/skills --skill property-patterns -a claude-code

2Вручную: положить файлы

~/.claude/skills/property-patterns/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/property-patterns/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора101

plan-ui-change Разбивает сложную страницу Blazor на отдельные компоненты до того, как агент начнёт писать код. Пригодится, когда в макете три и больше визуальных блоков. CX Codex +1 3 000установок collect-user-input Скилл для работы с формами в Blazor: EditForm, встроенные компоненты ввода, валидация и обработка отправки. Пригодится, когда нужно добавить форму, поиск или загрузку файлов. CX Codex +1 3 000установок coordinate-components Скилл учит агента связывать состояние компонентов Blazor без цепочек параметров от предка к потомку. Помогает настроить каскадные значения и сервисы со scope. CX Codex +1 3 000установок create-blazor-project Скилл проводит агента через выбор режима рендеринга Blazor и запускает dotnet new blazor с нужными флагами. CX Codex +1 3 000установок author-component Помогает проектировать и проверять компоненты Blazor без вызовов JavaScript. Пригодится при настройке параметров, слотов RenderFragment и асинхронного жизненного цикла. CX Codex +1 3 100установок test-analysis-extensions Справочный каталог файлов с таблицами для анализа тестов: маркеры, ассерты, пропуски, паттерны ожиданий. Агент читает нужный файл под язык проекта. CX Codex +1 3 100установок find-untested-sources Находит файлы исходного кода без тестов через статический анализ AST без сборки проекта. Пригодится агенту перед генерацией тестов, чтобы составить точный список пробелов. CX Codex +1 3 100установок fetch-and-send-data Помогает загружать и отправлять данные через API в Blazor-компонентах. Нужен для настройки HttpClient, состояний загрузки и обработки ошибок. CX Codex +1 3 100установок

Похожие

container-publish codewithmukesh Собирает OCI-образы прямо из dotnet publish /t:PublishContainer, без Dockerfile. Пригодится, когда проект на .NET 10 надо упаковать в контейнер и запушить в реестр. CX Codex +1 2 800установок vite-patterns affaan-m Скилл подсказывает, как настраивать Vite, плагины, HMR, переменные окружения и сборку. Нужен при работе с vite.config.ts и Vite-проектами. CX Codex +1 4 800установок dotnet-project-structure Aaronontheweb Скилл подсказывает агенту, как разложить .NET-решение: .slnx, Directory.Build.props, центральные версии пакетов и SourceLink. CX Codex +1 658установок project-structure codewithmukesh Скилл задаёт агенту правила раскладки .NET-решения: центральные версии пакетов, общие свойства сборки, формат .slnx и именование проектов. CX Codex +1 2 800установок dotnet-backend-patterns Seth Hobson Скилл для разработки на C# и .NET: паттерны асинхронного кода, внедрение зависимостей, Entity Framework Core, кэширование и тестирование. Нужен, если вы пишете backend API, MCP-серверы или рецензируете код на C#. CX Codex 19 076установок dotnet-patterns affaan-m Набор архитектурных правил C# и ASP.NET Core для ИИ-ассистентов. Задаёт стандарты написания чистого кода, работы с DI, асинхронностью и обработкой ошибок. CX Codex +1 4 600установок

Рядом в теме «DevOps и инфраструктура»

Всё по теме «DevOps и инфраструктура» →

Вопросы о property-patterns

Как установить property-patterns в Claude Code?

Выполните npx skills add dotnet/skills --skill property-patterns -a claude-code. Файл скилла появится по пути ~/.claude/skills/property-patterns/SKILL.md.

Что делает property-patterns?

Диагностирует и чинит дефекты свойств MSBuild: условия, дефолты, дописывание против перезаписи, проверки ОС и TFM, переносимые пути. Работает по проекту и по общим файлам вроде Directory.Build.*.

Почему условие по TargetFramework в .props не работает?

У проекта с одним таргетом $(TargetFramework) пустой в .props, пока не вычислено тело проекта. Поэтому такие группы ставят в .targets или в сам файл проекта.

Исходный текст

SKILL.md · MIT
---
name: property-patterns
description: "Diagnose and fix concrete MSBuild property defects in projects and existing shared-file hierarchies. USE FOR: conditions, defaults, append versus overwrite, last-write-wins values, OS/TFM checks, portable paths, normalization, and reviews centered on those property defects. Property defects in Directory.Build.* remain in scope, including overwritten values across parent/child imports and conditions that run before TargetFramework is set, even when the fix changes import order or moves a property group to .targets. DO NOT USE FOR: placement-only or import-only requests with no concrete property defect, such as discovering shared files or choosing which file owns a target or customization (use directory-build-organization); item operations; target structure; broad reviews without a concrete property defect; non-MSBuild work."
license: MIT
---

# MSBuild Property Patterns

Canonical property definition and manipulation patterns from the MSBuild repository.

## Conditional Defaults — The Foundational Pattern

Set a property **only if not already set**, allowing callers to override:

```xml
<PropertyGroup>
  <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
  <Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
  <BuildInParallel Condition="'$(BuildInParallel)' == ''">true</BuildInParallel>
</PropertyGroup>
```

### Rules

- Always quote both sides: `'$(Prop)' == ''`
- In `.props`: creates overridable defaults. In `.targets`: creates fallbacks.
- Properties without the condition **cannot be overridden** by earlier imports.

## Nested Conditional Groups

Group related properties under a shared condition:

```xml
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
  <DefineConstants>$(DefineConstants);FEATURE_APARTMENT_STATE</DefineConstants>
  <DefineConstants>$(DefineConstants);FEATURE_APM</DefineConstants>
  <FeatureAppDomain>true</FeatureAppDomain>
</PropertyGroup>

<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
  <NetCoreBuild>true</NetCoreBuild>
  <DefineConstants>$(DefineConstants);RUNTIME_TYPE_NETCORE</DefineConstants>
</PropertyGroup>
```

Use the outer `Condition` on `PropertyGroup` to avoid repeating the same condition on every property.

> **Warning:** `$(TargetFramework)` is empty in `.props` files for single-targeting projects until the project body is evaluated. Place `TargetFramework`-conditioned property groups in `.targets` files (or the project file itself), where the value is always available.

## Composition — Semicolon Concatenation

Properties that hold lists use semicolons. Always include the existing value when appending:

```xml
<PropertyGroup>
  <DefineConstants>$(DefineConstants);MY_FEATURE</DefineConstants>
  <NoWarn>$(NoWarn);NU5131;IDE0005</NoWarn>
  <LibraryTargetFrameworks>$(FullFrameworkTFM);$(LatestDotNetCoreForMSBuild);netstandard2.0</LibraryTargetFrameworks>
</PropertyGroup>
```

## Path Normalization and Trailing Slashes

```xml
<!-- Ensure trailing slash on directories -->
<PropertyGroup>
  <OutDir Condition="'$(OutDir)' != '' and !HasTrailingSlash('$(OutDir)')">$(OutDir)\</OutDir>
</PropertyGroup>

<!-- Normalize paths for cross-platform -->
<PropertyGroup>
  <TargetRefPath>$([MSBuild]::NormalizePath('$(TargetDir)', 'ref', '$(TargetFileName)'))</TargetRefPath>
</PropertyGroup>

<!-- Make relative path absolute -->
<PropertyGroup>
  <MSBuildProjectExtensionsPath
      Condition="'$([System.IO.Path]::IsPathRooted('$(MSBuildProjectExtensionsPath)'))' == 'false'">
    $([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(MSBuildProjectExtensionsPath)'))
  </MSBuildProjectExtensionsPath>
</PropertyGroup>
```

### Preferred path functions

| Function | Purpose |
|---|---|
| `$([MSBuild]::NormalizePath(...))` | Combine and normalize (cross-platform) |
| `$([System.IO.Path]::Combine(...))` | Combine path segments |
| `$([System.IO.Path]::IsPathRooted(...))` | Check if absolute |
| `HasTrailingSlash(...)` | Check for trailing slash |
| `$([MSBuild]::GetDirectoryNameOfFileAbove(...))` | Walk up directory tree |
| `$(MSBuildThisFileDirectory)` | Directory of current file |

## Target Framework Detection Helpers

```xml
<!-- Get TFM identifier -->
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
  <NetCoreBuild>true</NetCoreBuild>
</PropertyGroup>

<!-- Check TFM compatibility -->
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net472'))">
  <UseFrozenVersions>true</UseFrozenVersions>
</PropertyGroup>

<!-- OS detection -->
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
  <DefineConstants>$(DefineConstants);TEST_ISWINDOWS</DefineConstants>
</PropertyGroup>
```

## Guard Properties

Mark that a file has been imported to prevent double-imports:

```xml
<!-- At the end of MySDK.props -->
<PropertyGroup>
  <MySDKPropsImported>true</MySDKPropsImported>
</PropertyGroup>

<!-- At the top of MySDK.targets -->
<Import Project="MySDK.props" Condition="'$(MySDKPropsImported)' != 'true'" />
```

## Feature Gating by MSBuild Version

```xml
<PropertyGroup Condition="$([MSBuild]::AreFeaturesEnabled('17.10'))">
  <UseNewBehavior>true</UseNewBehavior>
</PropertyGroup>
```

## Fallback Chains

Set via primary source first, then fall back:

```xml
<PropertyGroup>
  <TlbExpPath>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkSdkFile('tlbexp.exe'))</TlbExpPath>
  <TlbExpPath Condition="'$(TlbExpPath)' == ''">$(_NetFxToolsDir)TlbExp.exe</TlbExpPath>
</PropertyGroup>
```

## Last Write Wins — Evaluation Order

MSBuild evaluates properties top-to-bottom. The last assignment wins:

```xml
<!-- File 1 (imported first) -->
<MyProp>value1</MyProp>        <!-- set to value1 -->
<!-- File 2 (imported second) -->
<MyProp>value2</MyProp>        <!-- overwritten to value2 -->
<!-- File 3 (imported third) -->
<MyProp Condition="'$(MyProp)' == ''">value3</MyProp>  <!-- NOT set — already value2 -->
```

Properties in `.targets` (imported late) override properties in `.props` (imported early) and the project file.

## Common Pitfalls

- **Unquoted conditions** (`$(X)==true`) fail when the property is empty. Always quote both sides.
- **Overwriting DefineConstants** (`<DefineConstants>MY_CONST</DefineConstants>`) drops all prior constants. Always append with `$(DefineConstants);`.
- **Hardcoded absolute paths** break portability. Use `$(MSBuildThisFileDirectory)` or `$([MSBuild]::NormalizePath(...))`.
- **Missing `Condition` on defaults** makes properties non-overridable. Add `Condition="'$(Prop)' == ''"` for values meant to be defaults.

© dotnet · MIT · dotnet/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой