Token导航 LogoToken导航

Agent Skill · 前端设计

dotnet-msbuild-tasks(dotnet msbuild 任务)

dotnet-msbuild-tasks 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

dotnet-msbuild-tasks 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为执行命令;许可证信息还不明确,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 7,754。

总安装 346周安装 14GitHub Stars 15下载 109核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:dotnet-msbuild-tasks(dotnet msbuild 任务)
来源仓库:https://github.com/wshaddix/dotnet-skills
仓库路径:skills/dotnet-msbuild-tasks
安装命令:
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-tasks
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-tasks

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。适合在需要围绕仓库状态或协作事项进行整理时使用。可结合来源仓库进一步核验具体用法。dotnet-msbuild-tasks 属于前端设计类 Skill,可作为该场景下的辅助能力补充。安装前建议确认权限范围与维护状态。

注意:IIncrementalTask 需 MSBuild 17.8+ 支持。

来源仓库内路径:skills/dotnet-msbuild-tasks

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要执行命令,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

dotnet-msbuild-tasks 怎么安装?

在终端执行 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-tasks。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

dotnet-msbuild-tasks 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

dotnet-msbuild-tasks 需要什么权限?

权限级别是执行命令。安装流程涉及命令执行,可能通过 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-tasks 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

dotnet-msbuild-tasks 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

dotnet-msbuild-tasks 用的人多吗?

公开数据是累计安装 346 次,近一周安装 14 次,下载 109 次,GitHub 15 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

dotnet-msbuild-tasks 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要执行命令,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 不能接受 Skill 在你机器上执行命令的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
dotnet-msbuild-tasks

dotnet msbuild 任务 · 本页

34615执行命令未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

dotnet-msbuild-tasks

Guidance for authoring custom MSBuild tasks: implementing the ITask interface, extending ToolTask for CLI wrappers, using IIncrementalTask (MSBuild 17.8+) for incremental execution, defining inline tasks with CodeTaskFactory, registering tasks via UsingTask, declaring task parameters, debugging tasks, and packaging tasks as NuGet packages.

Version assumptions:.NET 8.0+ SDK (MSBuild 17.8+). IIncrementalTask requires MSBuild 17.8+ (VS 2022 17.8+,.NET 8 SDK). All examples use SDK-style projects. All C# examples assume using Microsoft.Build.Framework; and using Microsoft.Build.Utilities; are in scope unless shown explicitly.

Scope boundary: This skill owns custom MSBuild task authoring -- ITask, ToolTask, IIncrementalTask, inline tasks, UsingTask, parameters, debugging, and NuGet packaging. MSBuild project system authoring (targets, props, items, conditions) is owned by [skill:dotnet-msbuild-authoring].

Cross-references: [skill:dotnet-msbuild-authoring] for custom targets, import ordering, items, conditions, and property functions.


ITask Interface

All MSBuild tasks implement Microsoft.Build.Framework.ITask. The simplest approach is to inherit from Microsoft.Build.Utilities.Task, which provides default implementations for BuildEngine and HostObject.

Minimal Custom Task

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class GenerateFileHash : Task
{
    [Required]
    public string InputFile { get; set; } = string.Empty;

    [Output]
    public string Hash { get; set; } = string.Empty;

    public override bool Execute()
    {
        if (!File.Exists(InputFile))
        {
            Log.LogError("Input file not found: {0}", InputFile);
            return false;
        }

        using var stream = File.OpenRead(InputFile);
        var bytes = System.Security.Cryptography.SHA256.HashData(stream);
        Hash = Convert.ToHexString(bytes).ToLowerInvariant();

        Log.LogMessage(MessageImportance.Normal,
            "SHA-256 hash for {0}: {1}", InputFile, Hash);
        return true;
    }
}

ITask Contract

MemberPurpose
BuildEngineProvides logging, error reporting, and build context
HostObjectHost-specific data (rarely used)
Execute()Runs the task. Return true for success, false for failure

The Task base class exposes a Log property (TaskLoggingHelper) with convenience methods:

MethodWhen to use
Log.LogMessage(importance, msg)Informational output (Normal, High, Low)
Log.LogWarning(msg)Non-fatal issues
Log.LogError(msg)Fatal errors (causes build failure)
Log.LogWarningFromException(ex)Warning from caught exception
Log.LogErrorFromException(ex)Error from caught exception

ToolTask Base Class

ToolTask extends Task for wrapping external command-line tools. It handles process invocation, output capture, and exit code interpretation.

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class RunLintTool : ToolTask
{
    [Required]
    public string SourceDirectory { get; set; } = string.Empty;

    public string Severity { get; set; } = "warning";

    // Required: name of the executable
    protected override string ToolName => "dotnet-lint";

    // Required: full path or tool name (OS resolves via PATH)
    protected override string GenerateFullPathToTool()
    {
        // Return tool name; the OS resolves it via PATH at process start
        return ToolName;
    }

    // Required: build the command-line arguments
    protected override string GenerateCommandLineCommands()
    {
        var builder = new CommandLineBuilder();
        builder.AppendSwitch("--check");
        builder.AppendSwitchIfNotNull("--severity ", Severity);
        builder.AppendFileNameIfNotNull(SourceDirectory);
        return builder.ToString();
    }

    // Optional: interpret non-zero exit codes
    protected override bool HandleTaskExecutionErrors()
    {
        Log.LogError("{0} found lint violations in {1}",
            ToolName, SourceDirectory);
        return false;
    }
}

Key ToolTask Overrides

OverridePurpose
ToolNameExecutable file name (e.g., dotnet-lint)
GenerateFullPathToTool()Full path to executable, or return ToolName to let the OS resolve via PATH
GenerateCommandLineCommands()Build argument string for the tool
GenerateResponseFileCommands()Arguments written to a response file (for long command lines)
HandleTaskExecutionErrors()Custom handling of non-zero exit codes
StandardOutputLoggingImportanceLog level for stdout (default: Low)
StandardErrorLoggingImportanceLog level for stderr (default: Normal)

Response Files for Long Command Lines

When the argument list is too long for the OS command line (common with many source files), use GenerateResponseFileCommands() to write arguments to a temporary response file:

protected override string GenerateResponseFileCommands()
{
    var builder = new CommandLineBuilder();
    // These arguments go into a @response.rsp file
    foreach (var source in SourceFiles)
    {
        builder.AppendFileNameIfNotNull(source.ItemSpec);
    }
    return builder.ToString();
}

protected override string GenerateCommandLineCommands()
{
    // These arguments stay on the command line (before the @file ref)
    var builder = new CommandLineBuilder();
    builder.AppendSwitchIfNotNull("--config ", ConfigFile);
    return builder.ToString();
}

MSBuild creates the response file, passes @responsefile.rsp to the tool, and cleans up afterward. The tool must support @file syntax (most.NET tools do).

When to use ToolTask vs Task: Use ToolTask when wrapping an external CLI tool. Use Task (ITask) when the logic is pure.NET code with no external process.


IIncrementalTask

Microsoft.Build.Framework.IIncrementalTask (MSBuild 17.8+, VS 2022 17.8+,.NET 8 SDK) signals to the MSBuild engine that a task supports receiving pre-filtered inputs. When a target declares Inputs/Outputs and the engine determines which inputs have changed, it passes only the changed items to an IIncrementalTask-implementing task instead of the full item list.

Version Gate

IIncrementalTask requires:

  • MSBuild 17.8+ (ships with VS 2022 17.8+)
  • .NET 8.0 SDK or later

Tasks targeting older MSBuild versions must not reference this interface. Use target-level Inputs/Outputs for incrementality on older versions. See [skill:dotnet-msbuild-authoring] for target-level incremental patterns.

How It Works

  1. The target declares Inputs and Outputs (required -- the engine uses these for change detection).
  2. MSBuild compares timestamps and determines which inputs are out of date.
  3. If the task implements IIncrementalTask, MSBuild passes only the changed items to the task's ITaskItem[] parameters instead of the full set.
  4. The task processes only those items -- no manual timestamp logic needed.

The FailIfIncrementalBuildIsNotPossible property controls fallback behavior:

  • false (default): If the engine cannot determine changed inputs (e.g., missing Outputs), it falls back to passing all inputs. The task runs in full-rebuild mode.
  • true: If the engine cannot provide incremental inputs, the task logs an error and fails. Use this when full rebuilds are unacceptably slow.

Implementation

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class TransformTemplates : Task, IIncrementalTask
{
    [Required]
    public ITaskItem[] Templates { get; set; } = [];

    [Output]
    public ITaskItem[] GeneratedFiles { get; set; } = [];

    // IIncrementalTask: if true, the task errors when the engine
    // cannot provide filtered inputs (falls back to full set if false)
    public bool FailIfIncrementalBuildIsNotPossible { get; set; }

    public override bool Execute()
    {
        // Templates contains ONLY changed items (filtered by engine)
        // when the target has Inputs/Outputs and incremental build is possible
        var outputs = new List<ITaskItem>();

        foreach (var template in Templates)
        {
            var inputPath = template.GetMetadata("FullPath");
            var outputPath = Path.ChangeExtension(inputPath, ".g.cs");

            var content = ProcessTemplate(File.ReadAllText(inputPath));
            File.WriteAllText(outputPath, content);

            Log.LogMessage(MessageImportance.Normal,
                "Transformed: {0} -> {1}", inputPath, outputPath);
            outputs.Add(new TaskItem(outputPath));
        }

        GeneratedFiles = outputs.ToArray();
        return true;
    }

    private static string ProcessTemplate(string input)
    {
        // Template transformation logic
        return $"// Auto-generated\n{input}";
    }
}
<!-- Target MUST declare Inputs/Outputs for engine-level change detection -->
<Target Name="TransformAllTemplates"
        BeforeTargets="CoreCompile"
        Inputs="@(Template)"
        Outputs="@(Template->'%(RootDir)%(Directory)%(Filename).g.cs')">
  <TransformTemplates Templates="@(Template)">
    <Output TaskParameter="GeneratedFiles" ItemName="Compile" />
  </TransformTemplates>
</Target>

IIncrementalTask vs target-level Inputs/Outputs alone: Without IIncrementalTask, target-level incrementality is all-or-nothing: if any input changed, the entire target re-runs with all items. With IIncrementalTask, the engine pre-filters the item list so the task receives only changed items, which is faster for targets that process large collections of files.


Task Parameters

Task parameters are public properties on the task class. MSBuild maps XML attributes to these properties automatically.

Parameter Attributes

AttributeEffect
[Required]Build fails if the parameter is not provided
[Output]Value is available to subsequent tasks/targets via %(TaskName.PropertyName)
No attributeOptional parameter with default value

Parameter Types

.NET TypeMSBuild XMLExample
stringScalar valueInputFile="src/app.cs"
booltrue/falseVerbose="true"
intNumeric valueMaxRetries="3"
string[]Semicolon-separatedAssemblies="a.dll;b.dll"
ITaskItemSingle itemSourceFile="@(MainSource)"
ITaskItem[]Item collectionSourceFiles="@(Compile)"

ITaskItem Metadata Access

ITaskItem carries rich metadata beyond the file path:

public class ProcessAssets : Task
{
    [Required]
    public ITaskItem[] Assets { get; set; } = [];

    [Output]
    public ITaskItem[] ProcessedAssets { get; set; } = [];

    public override bool Execute()
    {
        var results = new List<ITaskItem>();

        foreach (var asset in Assets)
        {
            // ItemSpec = the Include value (relative path)
            var relativePath = asset.ItemSpec;

            // Built-in metadata
            var fullPath = asset.GetMetadata("FullPath");
            var filename = asset.GetMetadata("Filename");
            var extension = asset.GetMetadata("Extension");

            // Custom metadata set in MSBuild XML
            var category = asset.GetMetadata("Category");

            Log.LogMessage(MessageImportance.Normal,
                "Processing {0} (category: {1})", filename, category);

            var output = new TaskItem(
                Path.ChangeExtension(fullPath, ".processed" + extension));
            // Copy all metadata from input to output
            asset.CopyMetadataTo(output);
            // Add new metadata
            output.SetMetadata("ProcessedAt",
                DateTime.UtcNow.ToString("o"));

            results.Add(output);
        }

        ProcessedAssets = results.ToArray();
        return true;
    }
}
<!-- MSBuild usage -->
<ItemGroup>
  <GameAsset Include="textures/*.png">
    <Category>texture</Category>
  </GameAsset>
  <GameAsset Include="models/*.fbx">
    <Category>model</Category>
  </GameAsset>
</ItemGroup>

<Target Name="ProcessGameAssets" BeforeTargets="Build">
  <ProcessAssets Assets="@(GameAsset)">
    <Output TaskParameter="ProcessedAssets" ItemName="ProcessedGameAsset" />
  </ProcessAssets>
</Target>

Inline Tasks (CodeTaskFactory)

For simple tasks that do not warrant a separate assembly, use CodeTaskFactory to define task logic inline in MSBuild XML. The code is compiled at build time.

<UsingTask TaskName="GetTimestamp"
           TaskFactory="CodeTaskFactory"
           AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
  <ParameterGroup>
    <Format ParameterType="System.String" Required="false" />
    <Timestamp ParameterType="System.String" Output="true" />
  </ParameterGroup>
  <Task>
    <Code Type="Fragment" Language="cs">
      <![CDATA[
        var format = string.IsNullOrEmpty(Format) ? "yyyyMMdd-HHmmss" : Format;
        Timestamp = DateTime.UtcNow.ToString(format);
      ]]>
    </Code>
  </Task>
</UsingTask>

<!-- Usage -->
<Target Name="StampBuild" BeforeTargets="CoreCompile">
  <GetTimestamp Format="yyyy.MMdd.HHmm">
    <Output TaskParameter="Timestamp" PropertyName="BuildTimestamp" />
  </GetTimestamp>
  <Message Importance="high" Text="Build timestamp: $(BuildTimestamp)" />
</Target>

CodeTaskFactory Code Types

TypeDescription
FragmentCode runs inside the Execute() method body. Access parameters as local variables.
MethodCode is a complete method body. Must include return true; or return false;.
ClassCode is a full class. Must implement ITask or inherit from Task.

Adding Assembly References

<UsingTask TaskName="ValidateJson"
           TaskFactory="CodeTaskFactory"
           AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
  <ParameterGroup>
    <JsonFile ParameterType="System.String" Required="true" />
    <IsValid ParameterType="System.Boolean" Output="true" />
  </ParameterGroup>
  <Task>
    <Reference Include="System.Text.Json" />
    <Code Type="Fragment" Language="cs">
      <![CDATA[
        try
        {
            var content = System.IO.File.ReadAllText(JsonFile);
            System.Text.Json.JsonDocument.Parse(content);
            IsValid = true;
        }
        catch (System.Text.Json.JsonException)
        {
            IsValid = false;
            Log.LogWarning("Invalid JSON: {0}", JsonFile);
        }
      ]]>
    </Code>
  </Task>
</UsingTask>

When to use inline tasks vs compiled tasks: Inline tasks are best for simple, self-contained logic (timestamps, file checks, string manipulation). For complex logic, multiple dependencies, or reuse across projects, compile a task assembly and distribute via NuGet.


UsingTask Registration

UsingTask tells MSBuild where to find a custom task implementation. It must appear before any target that uses the task.

From a Compiled Assembly

<!-- Register a task from a specific DLL -->
<UsingTask TaskName="MyCompany.Build.GenerateFileHash"
           AssemblyFile="$(MSBuildThisFileDirectory)..\tools\MyCompany.Build.Tasks.dll" />

<!-- Register using assembly name (GAC or resolved via AssemblySearchPaths) -->
<UsingTask TaskName="MyCompany.Build.GenerateFileHash"
           AssemblyName="MyCompany.Build.Tasks, Version=1.0.0.0, Culture=neutral" />

Task Name Resolution

AttributeValueEffect
TaskNameGenerateFileHashShort name; first match wins
TaskNameMyCompany.Build.GenerateFileHashFully qualified; exact match
AssemblyFileRelative or absolute pathLoad from file path
AssemblyNameStrong name or simple nameLoad by assembly identity

Use AssemblyFile with $(MSBuildThisFileDirectory) for tasks distributed via NuGet packages. The path resolves relative to the .targets file, not the consuming project.

Conditional Registration

<!-- Only register task when the assembly exists (e.g., optional tooling) -->
<UsingTask TaskName="MyCompany.Build.CodeGen"
           AssemblyFile="$(MSBuildThisFileDirectory)..\tools\MyCompany.Build.Tasks.dll"
           Condition="Exists('$(MSBuildThisFileDirectory)..\tools\MyCompany.Build.Tasks.dll')" />

Task Debugging

Debugging custom MSBuild tasks requires attaching a debugger to the MSBuild process.

MSBUILDDEBUGONSTART

Set the MSBUILDDEBUGONSTART environment variable before running the build:

ValueBehavior
1MSBuild calls Debugger.Launch() at startup -- shows the JIT debugger attach dialog
2MSBuild waits for a debugger to attach (prints PID to console), then continues
# Option 1: Launch debugger dialog (Windows)
set MSBUILDDEBUGONSTART=1
dotnet build

# Option 2: Wait for debugger attach (cross-platform)
export MSBUILDDEBUGONSTART=2
dotnet build
# MSBuild prints: "Waiting for debugger to attach (PID: 12345)..."
# Attach from VS or VS Code, then execution continues

Debugging Workflow

  1. Set MSBUILDDEBUGONSTART=2 in the terminal.
  2. Run dotnet build on the project that uses the custom task.
  3. MSBuild pauses and prints the process ID.
  4. Attach your debugger (Visual Studio: Debug > Attach to Process; VS Code:.NET Attach).
  5. Set breakpoints in the task's Execute() method.
  6. Continue execution -- the debugger hits your breakpoints.

Programmatic Debugger Launch

For development builds, add a conditional debugger launch inside the task:

public override bool Execute()
{
#if DEBUG
    if (!System.Diagnostics.Debugger.IsAttached)
    {
        System.Diagnostics.Debugger.Launch();
    }
#endif
    // Task logic ...
    return true;
}

Remove or guard debugger launches before publishing. Ship only Release builds of task assemblies. The #if DEBUG guard ensures no debugger prompts in production.


Task NuGet Packaging

Custom MSBuild tasks are typically distributed as NuGet packages. The package must place .props/.targets files and task assemblies in the correct folders.

Package Layout

MyCompany.Build.Tasks.nupkg
  build/
    MyCompany.Build.Tasks.props       (optional: set defaults)
    MyCompany.Build.Tasks.targets     (UsingTask + target definitions)
  buildTransitive/
    MyCompany.Build.Tasks.props       (optional: set defaults)
    MyCompany.Build.Tasks.targets     (UsingTask + target definitions)
  tools/
    net8.0/                           (matches csproj TargetFramework)
      MyCompany.Build.Tasks.dll       (task assembly)
      (other dependencies)

build vs buildTransitive

FolderScope
build/Targets/props apply to the direct consumer only
buildTransitive/Targets/props apply to the direct consumer and all projects that transitively reference it

Use buildTransitive/ for tasks that must run in every project in the dependency graph (e.g., code analyzers, source generators). Use build/ for tasks specific to the consuming project.

.targets File for NuGet Package

<!-- build/MyCompany.Build.Tasks.targets -->
<Project>
  <!-- TFM in path must match the csproj's TargetFramework -->
  <UsingTask TaskName="MyCompany.Build.GenerateFileHash"
             AssemblyFile="$(MSBuildThisFileDirectory)..\tools\net8.0\MyCompany.Build.Tasks.dll" />

  <Target Name="_MyCompanyHashOutputs"
          AfterTargets="Build"
          Condition="'$(GenerateOutputHashes)' == 'true'">
    <GenerateFileHash InputFile="$(TargetPath)">
      <Output TaskParameter="Hash" PropertyName="_OutputHash" />
    </GenerateFileHash>
    <Message Importance="high"
             Text="Output hash: $(_OutputHash)" />
  </Target>
</Project>

.props File for NuGet Package

<!-- build/MyCompany.Build.Tasks.props -->
<Project>
  <PropertyGroup>
    <!-- Default: consumers can override in their project file -->
    <GenerateOutputHashes Condition="'$(GenerateOutputHashes)' == ''">false</GenerateOutputHashes>
  </PropertyGroup>
</Project>

Project File for the Task Package

<!-- MyCompany.Build.Tasks.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <IsPackable>true</IsPackable>
    <PackageId>MyCompany.Build.Tasks</PackageId>
    <PackageVersion>1.0.0</PackageVersion>
    <Description>Custom MSBuild tasks for MyCompany build pipeline</Description>

    <!-- Do not add as a lib dependency -->
    <IncludeBuildOutput>false</IncludeBuildOutput>

    <!-- Suppress NU5100: task DLLs are in tools/, not lib/ -->
    <NoWarn>$(NoWarn);NU5100</NoWarn>

    <!-- Mark as a development dependency -->
    <DevelopmentDependency>true</DevelopmentDependency>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Build.Framework" Version="17.8.3"
                      PrivateAssets="all" />
    <PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.8.3"
                      PrivateAssets="all" />
  </ItemGroup>

  <!-- Pack task assembly into tools/ (uses TFM from project) -->
  <ItemGroup>
    <None Include="$(OutputPath)/**/*.dll" Pack="true"
          PackagePath="tools/$(TargetFramework)/" />
  </ItemGroup>

  <!-- Pack .props and .targets into build/ and buildTransitive/ -->
  <ItemGroup>
    <None Include="build/**" Pack="true" PackagePath="build/" />
    <None Include="buildTransitive/**" Pack="true" PackagePath="buildTransitive/" />
  </ItemGroup>
</Project>

Key csproj settings:

  • IncludeBuildOutput=false prevents the task DLL from appearing in the lib/ folder (which would add it as a compile reference to consumers).
  • DevelopmentDependency=true marks the package as build-time only, so it does not flow to consumers' runtime dependencies.
  • PrivateAssets="all" on MSBuild framework references prevents them from becoming transitive dependencies.

Agent Gotchas

  1. Returning false without logging an error. If Execute() returns false but Log.LogError was never called, MSBuild reports a generic "task failed" with no actionable message. Always log an error before returning false.
  2. Using Console.WriteLine instead of Log.LogMessage. Console output bypasses MSBuild's logging infrastructure and may not appear in build logs, binary logs, or IDE error lists. Always use Log.LogMessage, Log.LogWarning, or Log.LogError.
  3. Referencing IIncrementalTask without version-gating. This interface requires MSBuild 17.8+ (.NET 8 SDK). Tasks referencing it will fail to load on older MSBuild versions with a TypeLoadException. If supporting older SDKs, use target-level Inputs/Outputs instead. If the task must support both old and new MSBuild, ship separate task assemblies per MSBuild version range or use #if conditional compilation with a version constant.
  4. Placing task DLLs in the NuGet lib/ folder. This adds the assembly as a compile reference to consuming projects, polluting their type namespace. Set IncludeBuildOutput=false and pack into tools/ instead.
  5. Forgetting PrivateAssets="all" on MSBuild framework package references. Without it, Microsoft.Build.Framework and Microsoft.Build.Utilities.Core become transitive dependencies of consuming projects, causing version conflicts.
  6. Using AssemblyFile with a path relative to the project. In NuGet packages, the .targets file is in a different location than the consuming project. Use $(MSBuildThisFileDirectory) to build paths relative to the .targets file itself.
  7. Leaving Debugger.Launch() in release builds. Shipping a task with unconditional Debugger.Launch() halts builds on CI/CD servers. Guard with #if DEBUG or remove before packaging.
  8. Inline tasks with complex dependencies. CodeTaskFactory compiles code at build time with limited assembly references. For tasks that need NuGet packages or complex type hierarchies, compile a standalone task assembly instead.

References

平台分布

Codex

36.72%
按下载量换算40

Claude

32.32%
按下载量换算35

Cursor

19.58%
按下载量换算21

Gemini CLI

8.4%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-tasks 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills