Skip to main content

revit-templates-sdk

Author the Nice3point.Revit.Sdk MSBuild SDK that scaffolded Revit add-ins build against, covering its props and targets contract and the C# MSBuild task classes. USE FOR: parsing the configuration into a Revit version and selecting the target framework, emitting REVIT#### and REVIT####_OR_GREATER constants, adding conditional implicit usings, patching the add-in manifest, publishing and repacking output, and supporting .NET compability. DO NOT USE FOR: declaring template options or conditional content in the template package; consuming the SDK to build an add-in.

Zur Installation springen

Quellinformationen

Repository
Nice3point/RevitTemplates
Letzte Quellaktivität
23. Juli 2026 um 20:46
Erkannte Sprache von SKILL.md
Englisch
Sterne
457
Forks
66

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
revit-templates-sdk
description
Author the Nice3point.Revit.Sdk MSBuild SDK that scaffolded Revit add-ins build against, covering its props and targets contract and the C# MSBuild task classes. USE FOR: parsing the configuration into a Revit version and selecting the target framework, emitting REVIT#### and REVIT####_OR_GREATER constants, adding conditional implicit usings, patching the add-in manifest, publishing and repacking output, and supporting .NET compability. DO NOT USE FOR: declaring template options or conditional content in the template package; consuming the SDK to build an add-in.
license
MIT
# Revit Templates SDK `Nice3point.Revit.Sdk` is the custom MSBuild SDK a scaffolded add-in sets through `Sdk="Nice3point.Revit.Sdk"`; the project file stays almost empty and the SDK derives the rest from the active configuration. It lives in `source/Nice3point.Revit.Sdk`: the props and targets contract in `Sdk/`, and the MSBuild task classes at the project root. The SDK owns the multi-version build; that logic is never duplicated into template content. ## When to use - Changing configuration parsing, target-framework selection, or the version constants. - Changing the implicit usings, manifest patching, publishing, or repacking targets. - Adding or changing an MSBuild task class in the SDK assembly. ## When not to use - Declaring a scaffolding option or conditional content. That is template work; see `revit-templates-authoring`. ## Workflow ### Step 1: Keep the props and targets import order `Sdk/Sdk.props` imports the Microsoft SDK props first, then the SDK's own `Nice3point.Revit.Common.props`; `Sdk/Sdk.targets` imports `Nice3point.Revit.Common.targets`, then the Microsoft SDK targets, then each feature target file. Order the SDK around the standard build; do not fight it. A feature target hooks the standard build through `AfterTargets` / `BeforeTargets`, never by replacing a built-in target. ### Step 2: Derive the Revit version and target framework in Common.props `Nice3point.Revit.Common.props` parses the trailing number of the configuration name, normalizes a two-digit form to the full year, and falls back to `-1` when none is present. `Nice3point.Revit.Common.targets` raises `ValidateRevitVersion` when the version is unresolved; a misnamed configuration fails cleanly. ```xml <_RevitConfigurationVersion>$([System.Text.RegularExpressions.Regex]::Match($(Configuration), '(\d+)(?!.*\d)').Value)</_RevitConfigurationVersion> <RevitVersion Condition="'$(_RevitConfigurationVersion.Length)' == '4'">$(_RevitConfigurationVersion)</RevitVersion> <RevitVersion Condition="'$(_RevitConfigurationVersion.Length)' == '2'">20$(_RevitConfigurationVersion)</RevitVersion> <RevitVersion Condition="'$(RevitVersion)' == ''">-1</RevitVersion> ``` The `TargetFramework` is then selected by `RevitVersion` thresholds; one project targets the right framework per configuration. ### Step 3: Write an MSBuild task class that returns, never throws A task class derives from `Microsoft.Build.Utilities.Task`, carries `[PublicAPI]`, and lives at the SDK project root. Mark an input MSBuild must supply `[Required]` and a value the task hands back `[Output]`. `Execute` wraps its body in a `try`/`catch`, logs a failure and returns `false`, and returns `true` as a no-op when there is nothing to do; a build step fails cleanly, not by crashing the build host. ```csharp [PublicAPI] public class GenerateCompatibleDefineConstants : Task { [Required] public required string Configuration { get; set; } public string[] Configurations { get; set; } = []; public string? RevitVersion { get; set; } [Output] public string[]? DefineConstants { get; private set; } public override bool Execute() { try { int currentVersion; if (string.IsNullOrEmpty(RevitVersion)) { if (!TryGetRevitVersion(Configuration, out currentVersion)) return true; } else { if (!int.TryParse(RevitVersion, out currentVersion)) return true; } //Business logic ... return true; } catch (Exception exception) { Log.LogErrorFromException(exception, false); return false; } } } ``` This task emits `REVIT####` for the active version and `REVIT####_OR_GREATER` for it and every earlier configuration; template content gates version-specific Revit APIs with `#if REVIT2024_OR_GREATER`. ### Step 4: Register the task and hook it from a feature target Register each task with `UsingTask` in `Sdk.props`, keyed off the SDK name and the task assembly folder resolved in Step 6. ```xml <UsingTask TaskName="$(MSBuildThisFileName).GenerateCompatibleDefineConstants" AssemblyFile="$(BuildTasksAssembly)"/> ``` Invoke it from a feature target ordered against the standard build, and route its `[Output]` into the property or item it feeds. ```xml <Target Name="GenerateRevitCompatibleDefineConstants" AfterTargets="AddImplicitDefineConstants" Condition="'$(DisableImplicitRevitDefines)' != 'true'"> <GenerateCompatibleDefineConstants RevitVersion="$(RevitVersion)" Configuration="$(Configuration)" Configurations="$(Configurations)"> <Output TaskParameter="DefineConstants" ItemName="_ImplicitRevitDefineConstant"/> </GenerateCompatibleDefineConstants> <PropertyGroup> <DefineConstants Condition="'@(_ImplicitRevitDefineConstant)' != ''">$(DefineConstants);@(_ImplicitRevitDefineConstant)</DefineConstants> </PropertyGroup> </Target> ``` ### Step 5: Keep the task assembly loadable under every build host `Nice3point.Revit.Sdk.csproj` multi-targets `net48;netstandard2.0;net10.0`; the assembly loads under MSBuild on .NET Framework, older .NET Core hosts, and the latest SDK. `Sdk.props` picks the matching folder before registering the tasks. ```xml <BuildTasksTFM Condition="'$(MSBuildRuntimeType)' == 'Core' AND $([MSBuild]::VersionGreaterThanOrEquals($(NETCoreSdkVersion), '10.0'))">net10.0</BuildTasksTFM> <BuildTasksTFM Condition="'$(MSBuildRuntimeType)' == 'Core' AND '$(BuildTasksTFM)' == ''">netstandard2.0</BuildTasksTFM> <BuildTasksTFM Condition="'$(BuildTasksTFM)' == ''">net48</BuildTasksTFM> ``` ### Step 6: Verify against the build and keep the README in sync The SDK package README is sourced from `wiki/MsBuild-Sdk.md` through the csproj `PackageReadmeFile`; a change to the public property surface or a feature updates that wiki page in the same commit. Verify by running the template test from the `build` directory, which scaffolds projects across the option matrix and compiles each against the SDK. ```shell dotnet run -- test ``` ## Validation - [ ] `Sdk.props` and `Sdk.targets` keep the import order, and every feature target hooks the standard build through `AfterTargets` / `BeforeTargets`. - [ ] `RevitVersion` and `TargetFramework` derive from the configuration, and an unresolved version fails through `ValidateRevitVersion`. - [ ] Every public task class carries `[PublicAPI]`, marks inputs `[Required]` and results `[Output]`, and returns `false` on failure without throwing. - [ ] Each task is registered with `UsingTask` and invoked from a correctly ordered feature target. - [ ] The csproj still multi-targets, and `Sdk.props` selects the matching task folder. - [ ] `wiki/MsBuild-Sdk.md` reflects any public property or feature change, and `dotnet run -- test` compiles the scaffolded matrix. ## Common Pitfalls | Pitfall | Correct approach | |--------------------------------------------------------------|-----------------------------------------------------------------------------------------------| | Throwing from a task on bad input | Return `true` as a no-op when nothing applies, and `false` after `Log.LogErrorFromException`. | | Replacing a built-in target | Hook the standard build with `AfterTargets` / `BeforeTargets` so the SDK orders around it. | | Dropping a task TFM from the csproj | Keep `net48;netstandard2.0;net10.0`; the assembly loads under every MSBuild host. | | Duplicating build logic into template content | Author configuration parsing, TFM selection, constants, and publishing once in the SDK. | | Renaming a public SDK property or task without a deprecation | The SDK surface is a contract; rename only through a deprecation path and keep `[PublicAPI]`. | | Editing the packed README directly | Update `wiki/MsBuild-Sdk.md`; the csproj sources the package README from it. |
Auf GitHub ansehen