Agent Skillsdotnet/skills › target-authoring

target-authoring

GitHub

提供MSBuild自定义Target编写的标准模式,涵盖链式扩展、依赖管理及错误处理。用于诊断和修复Target编写反模式,如错误覆盖SDK目标、Inputs/Outputs缺失导致的构建问题及Returns误用等场景。

plugins/dotnet-msbuild/skills/target-authoring/SKILL.md dotnet/skills

触发场景

编写或修改MSBuild .targets文件 排查MSBuild构建链断裂或静默重写问题 优化MSBuild增量构建与依赖关系

安装

npx skills add dotnet/skills --skill target-authoring -g -y
更多选项

非标准路径

npx skills add https://github.com/dotnet/skills/tree/main/plugins/dotnet-msbuild/skills/target-authoring -g -y

不安装直接使用

npx skills use dotnet/skills@target-authoring

指定 Agent (Claude Code)

npx skills add dotnet/skills --skill target-authoring -a claude-code -g -y

安装 repo 全部 skill

npx skills add dotnet/skills --all -g -y

预览 repo 内 skill

npx skills add dotnet/skills --list

SKILL.md

Frontmatter
{
    "name": "target-authoring",
    "license": "MIT",
    "description": "Canonical patterns for writing custom MSBuild targets. USE FOR: diagnosing and fixing custom target authoring anti-patterns; broken SDK target chains across files (e.g., Directory.Build.targets silently redefining SDK targets); targets that replace CompileDependsOn instead of extending it with $(CompileDependsOn); query targets returning stale results from Outputs vs Returns misuse; missing Inputs\/Outputs causing unnecessary rebuilds; missing FileWrites registration. Covers DependsOnTargets vs BeforeTargets vs AfterTargets, the Build→CoreBuild three-level pattern, and the $(XxxDependsOn) chain-extension pattern. DO NOT USE FOR: incremental build tuning (use incremental-build), parallelization (use build-parallelism), general anti-patterns (use msbuild-antipatterns), non-MSBuild build systems."
}

Custom Target Authoring Patterns

Canonical patterns from Microsoft.Common.CurrentVersion.targets in the MSBuild repository.

The Three-Level Target Chain

Every major entry point (Build, Rebuild, Clean) delegates to a property listing its dependencies, which chains through Before → Core → After:

<PropertyGroup>
  <BuildDependsOn>
    BeforeBuild;
    CoreBuild;
    AfterBuild
  </BuildDependsOn>
</PropertyGroup>

<Target Name="Build"
    Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
    DependsOnTargets="$(BuildDependsOn)"
    Returns="@(TargetPathWithTargetPlatformMoniker)" />

<!-- Empty extensibility targets — users override these -->
<Target Name="BeforeBuild" />
<Target Name="AfterBuild" />

CoreBuild delegates to $(CoreBuildDependsOn) and includes error handlers:

<Target Name="CoreBuild" DependsOnTargets="$(CoreBuildDependsOn)">
  <OnError ExecuteTargets="_TimeStampAfterCompile;PostBuildEvent"
      Condition="'$(RunPostBuildEvent)' == 'Always'" />
  <OnError ExecuteTargets="_CleanRecordFileWrites" />
</Target>

Rules

  • Delegate to a property (DependsOnTargets="$(MyTargetDependsOn)"), not hardcoded targets.
  • OnError goes inside the orchestrating target to ensure cleanup runs even on failure.
  • Empty Before/After targets are extensibility points. Users override them; SDKs never put logic in them.

Chain Extension — Append, Never Overwrite

When adding a custom target to an existing chain, append to the DependsOn property:

<!-- GOOD: Append to existing chain -->
<PropertyGroup>
  <CompileDependsOn>$(CompileDependsOn);MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>

<!-- BAD: Overwrites the entire chain, dropping SDK targets -->
<PropertyGroup>
  <CompileDependsOn>MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>

DependsOnTargets vs BeforeTargets vs AfterTargets

Mechanism Defined in Best for
DependsOnTargets The target that needs deps Target explicitly requires others
BeforeTargets The injecting target Insert before a target you don't own
AfterTargets The injecting target Insert after a target you don't own

Validation targets use BeforeTargets to intercept all entry points:

<Target Name="_CheckForInvalidConfigurationAndPlatform"
    BeforeTargets="$(BuildDependsOn);Build;$(RebuildDependsOn);Rebuild;$(CleanDependsOn);Clean">
</Target>

Rules:

  • Use DependsOnTargets when your target needs specific prerequisites.
  • Use BeforeTargets/AfterTargets when injecting into a pipeline you don't own.
  • Prefer BeforeTargets="CoreCompile" over modifying $(CompileDependsOn) when you don't control the targets file.

Returns vs Outputs

<!-- Build returns items for consumption by referencing projects -->
<Target Name="Build"
    DependsOnTargets="$(BuildDependsOn)"
    Returns="@(TargetPathWithTargetPlatformMoniker)" />

<!-- GetTargetPath is a lightweight query target -->
<Target Name="GetTargetPath" Returns="@(TargetPathWithTargetPlatformMoniker)" />
  • Returns specifies what the MSBuild task receives when calling this project. Use for inter-project communication.
  • Outputs on inner targets is for incrementality (timestamp checks). Use for up-to-date detection.
  • Never mix the two purposes. Query targets (GetTargetPath, GetTargetFrameworks) should use Returns, not Outputs.

Target Naming Conventions

Pattern Meaning Example
_PrefixedName Internal/private target _TimeStampBeforeCompile
CoreXxx The actual implementation CoreBuild, CoreCompile
BeforeXxx / AfterXxx Empty extensibility hooks BeforeBuild, AfterCompile
PrepareXxx Setup/validation phase PrepareForBuild
ResolveXxx Discovery/resolution phase ResolveReferences
GetXxx Lightweight query (no side effects) GetTargetPath

Complete Custom Target Template

<!-- 1. Define the DependsOn chain for extensibility -->
<PropertyGroup>
  <MyFeatureDependsOn>
    _ValidateMyFeatureInputs;
    BeforeMyFeature;
    CoreMyFeature;
    AfterMyFeature
  </MyFeatureDependsOn>
</PropertyGroup>

<!-- 2. Outer target with Returns for inter-project communication -->
<Target Name="MyFeature"
    DependsOnTargets="$(MyFeatureDependsOn)"
    Returns="@(MyFeatureOutput)" />

<!-- 3. Empty extensibility points -->
<Target Name="BeforeMyFeature" />
<Target Name="AfterMyFeature" />

<!-- 4. Core implementation with Inputs/Outputs for incrementality -->
<Target Name="CoreMyFeature"
    Inputs="$(MSBuildAllProjects);@(MyFeatureInput)"
    Outputs="$(IntermediateOutputPath)myfeature.generated.cs">
  <Exec Command="my-tool.exe -o $(IntermediateOutputPath)myfeature.generated.cs" />
  <!-- 5. Register outputs for clean tracking -->
  <ItemGroup>
    <Compile Include="$(IntermediateOutputPath)myfeature.generated.cs" />
    <FileWrites Include="$(IntermediateOutputPath)myfeature.generated.cs" />
  </ItemGroup>
</Target>

<!-- 6. Validation target runs first in the dependency chain -->
<Target Name="_ValidateMyFeatureInputs">
  <Error Text="MyFeatureInput items are required."
         Condition="'@(MyFeatureInput)' == ''" />
</Target>

Common Pitfalls

  • Overwriting DependsOn properties drops SDK targets silently. Always include $(ExistingProperty) when appending.
  • Using Outputs on query targets causes MSBuild to skip them when "up to date," returning stale data. Use Returns.
  • Defining targets in .props means BeforeTargets on SDK targets have nothing to hook into yet. Move targets to .targets.
  • Forgetting OnError in orchestrating targets means file tracking fails on build errors, breaking subsequent incremental builds.

版本历史

  • 5354047 当前 2026-07-23 12:08

    精简Description以节省技能菜单预算空间,优化路由描述清晰度。

  • ce75c35 2026-07-06 00:32

同 Skill 集合

.agents/skills/create-custom-agent/SKILL.md
.agents/skills/create-skill-test/SKILL.md
.agents/skills/create-skill/SKILL.md
.agents/skills/improve-skill-quality/SKILL.md
.github/skills/agentic-workflows/SKILL.md
eng/skill-validator/tests/fixtures/sample-skill/SKILL.md
plugins/dotnet-advanced/skills/csharp-scripts/SKILL.md
plugins/dotnet-advanced/skills/nuget-trusted-publishing/SKILL.md
plugins/dotnet-aspnetcore/skills/configuring-opentelemetry-dotnet/SKILL.md
plugins/dotnet-aspnetcore/skills/dotnet-webapi/SKILL.md
plugins/dotnet-aspnetcore/skills/minimal-api-file-upload/SKILL.md
plugins/dotnet-blazor/skills/create-blazor-project/SKILL.md
plugins/dotnet-blazor/skills/fetch-and-send-data/SKILL.md
plugins/dotnet-blazor/skills/support-prerendering/SKILL.md
plugins/dotnet-blazor/skills/use-js-interop/SKILL.md
plugins/dotnet-data/skills/optimizing-ef-core-queries/SKILL.md
plugins/dotnet-diag/skills/analyzing-dotnet-performance/SKILL.md
plugins/dotnet-diag/skills/clr-activation-debugging/SKILL.md
plugins/dotnet-diag/skills/dotnet-trace-collect/SKILL.md
plugins/dotnet-diag/skills/dump-collect/SKILL.md
plugins/dotnet-experimental/skills/exp-mock-usage-analysis/SKILL.md
plugins/dotnet-experimental/skills/exp-simd-vectorization/SKILL.md
plugins/dotnet-msbuild/skills/binlog-failure-analysis/SKILL.md
plugins/dotnet-msbuild/skills/copy-to-output-directory/SKILL.md
plugins/dotnet-msbuild/skills/msbuild-server/SKILL.md
plugins/dotnet-msbuild/skills/resolve-project-references/SKILL.md
plugins/dotnet-test-migration/skills/migrate-xunit-to-mstest/SKILL.md
plugins/dotnet-test-migration/skills/migrate-xunit-to-xunit-v3/SKILL.md
plugins/dotnet-test/skills/code-testing-extensions/SKILL.md
plugins/dotnet-test/skills/filter-syntax/SKILL.md
plugins/dotnet-test/skills/find-untested-sources/SKILL.md
plugins/dotnet-test/skills/platform-detection/SKILL.md
plugins/dotnet-upgrade/skills/dotnet-aot-compat/SKILL.md
.agents/skills/authoring-github-workflows/SKILL.md
plugins/dotnet-advanced/skills/dotnet-pinvoke/SKILL.md
plugins/dotnet-ai/skills/mcp-csharp-create/SKILL.md
plugins/dotnet-ai/skills/mcp-csharp-debug/SKILL.md
plugins/dotnet-ai/skills/mcp-csharp-test/SKILL.md
plugins/dotnet-ai/skills/technology-selection/SKILL.md
plugins/dotnet-aspnetcore/skills/convert-blazor-server-to-webapp/SKILL.md
plugins/dotnet-blazor/skills/author-component/SKILL.md
plugins/dotnet-blazor/skills/collect-user-input/SKILL.md
plugins/dotnet-blazor/skills/configure-auth/SKILL.md
plugins/dotnet-blazor/skills/coordinate-components/SKILL.md
plugins/dotnet-blazor/skills/plan-ui-change/SKILL.md
plugins/dotnet-data/skills/create-datadriven-aspnetcore/SKILL.md
plugins/dotnet-diag/skills/android-tombstone-symbolication/SKILL.md
plugins/dotnet-diag/skills/apple-crash-symbolication/SKILL.md
plugins/dotnet-diag/skills/microbenchmarking/SKILL.md
plugins/dotnet-experimental/skills/exp-test-maintainability/SKILL.md

元信息

文件数
0
版本
aa3c4ab
Hash
e39b9ad0
收录时间
2026-07-06 00:32

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-09 05:44
浙ICP备14020137号-1 $访客地图$