A strongly-typed, fluent DSL for authoring MSBuild packages in C#
Author MSBuild .props, .targets, and SDK assets using a strongly-typed fluent API in C#, then automatically generate 100% standard MSBuild XML during build. No more hand-editing XML - write refactorable, testable, type-safe C# code instead.
- Introduction - Project overview and core concepts
- Getting Started - Installation and quick start guide
- User Guides - Detailed tutorials and patterns
- API Reference - Complete API documentation
- Migration Guide - Convert existing XML to fluent API
- π― Strongly-typed fluent API - IntelliSense, refactoring, compile-time validation
- π Automatic build integration - Generate MSBuild assets during
dotnet build, no CLI required - π¦ Full NuGet layout support -
build/,buildTransitive/, andSdk/folders - π§ XML scaffolding - Convert existing XML to fluent code with
jdmsbuild scaffold - β Production-tested - Validated against real-world MSBuild packages
- π Deterministic output - Consistent XML generation for meaningful diffs
<PackageReference Include="JD.MSBuild.Fluent" Version="*" />using JD.MSBuild.Fluent;
using JD.MSBuild.Fluent.Fluent;
namespace MySdk;
public static class DefinitionFactory
{
public static PackageDefinition Create() => Package.Define("MySdk")
.Props(p => p
.Property("MySdkEnabled", "true")
.Property("MySdkVersion", "1.0.0"))
.Targets(t => t
.Target("MySdk_Hello", target => target
.BeforeTargets("Build")
.Condition("'$(MySdkEnabled)' == 'true'")
.Message("Hello from MySdk v$(MySdkVersion)!", "High")))
.Pack(o => {
o.BuildTransitive = true;
o.EmitSdk = true;
})
.Build();
}MSBuild assets are automatically generated during build and packaged correctly:
- β
build/MySdk.props - β
build/MySdk.targets - β
buildTransitive/MySdk.propsand.targets(if enabled) - β
Sdk/MySdk/Sdk.propsandSdk.targets(if SDK enabled)
No CLI required! Just build and pack:
dotnet build
dotnet pack<PropertyGroup>
<!-- Enable/disable generation (default: true) -->
<JDMSBuildFluentGenerateEnabled>true</JDMSBuildFluentGenerateEnabled>
<!-- Specify factory type (default: auto-detect) -->
<JDMSBuildFluentDefinitionType>MySdk.DefinitionFactory</JDMSBuildFluentDefinitionType>
<!-- Output directory (default: obj/msbuild) -->
<JDMSBuildFluentOutputDir>$(MSBuildProjectDirectory)\msbuild</JDMSBuildFluentOutputDir>
</PropertyGroup>Convert existing MSBuild XML files to fluent API:
# Install CLI tool
dotnet tool install -g JD.MSBuild.Fluent.Cli
# Scaffold from existing XML
jdmsbuild scaffold --xml MyPackage.targets --output DefinitionFactory.cs --package-id MyCompany.MyPackageBefore (XML):
<Project>
<PropertyGroup>
<MyPackageVersion>1.0.0</MyPackageVersion>
</PropertyGroup>
<Target Name="Hello" BeforeTargets="Build">
<Message Text="Hello from MyPackage v$(MyPackageVersion)!" Importance="High" />
</Target>
</Project>After (Fluent C#):
public static PackageDefinition Create()
{
return Package.Define("MyPackage")
.Targets(t =>
{
t.PropertyGroup(null, group =>
{
group.Property("MyPackageVersion", "1.0.0");
});
t.Target("Hello", target =>
{
target.BeforeTargets("Build");
target.Message("Hello from MyPackage v$(MyPackageVersion)!", "High");
});
})
.Build();
}Now you can refactor, test, and maintain your MSBuild logic like regular C# code!
- β No IntelliSense or type safety
- β No refactoring support
- β Hard to test and validate
- β Copy-paste leads to duplication
- β Difficult to review diffs
- β Strongly-typed API with full IntelliSense
- β Refactoring support - rename, extract, move
- β Unit testable - validate logic before publishing
- β DRY principle - reuse patterns across targets
- β Better diffs - meaningful C# changes instead of XML noise
- β Automatic generation - integrated into build pipeline
The CLI is optional for advanced scenarios. Most users don't need it since generation happens automatically during build.
# Install globally
dotnet tool install -g JD.MSBuild.Fluent.Cli
# Generate assets manually
jdmsbuild generate --assembly path/to/MySdk.dll --type MySdk.DefinitionFactory --output msbuild
# Generate built-in example
jdmsbuild generate --example --output artifacts/msbuild
# Scaffold from XML
jdmsbuild scaffold --xml MyPackage.targets --output DefinitionFactory.csGenerated files follow standard NuGet conventions:
build/
MySdk.props β Applied to direct consumers
MySdk.targets β Applied to direct consumers
buildTransitive/ β (optional)
MySdk.props β Applied transitively
MySdk.targets β Applied transitively
Sdk/ β (optional)
MySdk/
Sdk.props β SDK-style project support
Sdk.targets β SDK-style project support
samples/MinimalSdkPackage- Complete end-to-end example- Integration tests validate against JD.Efcpt.Build (real-world production package)
The XML renderer produces deterministic, canonical output:
- Consistent property ordering
- Consistent item metadata ordering
- Consistent task parameter ordering
- Meaningful diffs across versions
Contributions welcome! This project follows standard GitHub flow:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Submit a pull request
- JD.Efcpt.Build - EF Core Power Tools build integration (uses JD.MSBuild.Fluent)
- JD.MSBuild.Containers - Docker container build integration