Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
NuGet package authoring for .NET library authors: SDK-style .csproj package properties (PackageId, PackageTags,
PackageReadmeFile, PackageLicenseExpression), source generator NuGet packaging with analyzers/dotnet/cs/ folder
layout and buildTransitive targets, multi-TFM packages, symbol packages (snupkg) with deterministic builds, package
signing (author signing with certificates, repository signing), package validation (EnablePackageValidation,
Microsoft.DotNet.ApiCompat.Task for API compatibility), and NuGet versioning strategies (SemVer 2.0, pre-release
suffixes, NBGV integration).
Version assumptions: .NET 8.0+ baseline. NuGet client bundled with .NET 8+ SDK. Microsoft.DotNet.ApiCompat.Task
8.0+ for API compatibility validation.
Scope
SDK-style csproj package properties and metadata
Source generator NuGet packaging with analyzers folder layout
Multi-TFM packages and symbol packages (snupkg)
Package signing (author and repository signing)
Package validation (EnablePackageValidation, API compatibility)
NuGet versioning strategies (SemVer 2.0, NBGV)
Out of scope
Central Package Management, SourceLink, nuget.config -- see [skill:dotnet-project-structure]
CI/CD NuGet push workflows -- see [skill:dotnet-gha-publish] and [skill:dotnet-ado-publish]
CLI tool packaging and distribution -- see [skill:dotnet-cli-packaging]
Roslyn analyzer authoring -- see [skill:dotnet-roslyn-analyzers]
Release lifecycle and NBGV setup -- see [skill:dotnet-release-management]
Cross-references: [skill:dotnet-project-structure] for CPM, SourceLink, nuget.config, [skill:dotnet-gha-publish] for CI
NuGet push workflows, [skill:dotnet-ado-publish] for ADO NuGet push workflows, [skill:dotnet-cli-packaging] for CLI tool
distribution formats, [skill:dotnet-csharp-source-generators] for Roslyn source generator authoring,
[skill:dotnet-release-management] for release lifecycle and NBGV setup, [skill:dotnet-roslyn-analyzers] for Roslyn
analyzer authoring.
SDK-Style Package Properties
Every NuGet package starts with MSBuild properties in the .csproj. SDK-style projects produce NuGet packages with
dotnet pack -- no .nuspec file required.
Essential Package Metadata
< =>
net8.0
MyCompany.Widgets
1.0.0
My Company
A library for managing widgets with fluent API support.
widgets;fluent;dotnet
MIT
https://github.com/mycompany/widgets
https://github.com/mycompany/widgets
git
README.md
icon.png
true
true
```markdown
### Property Reference
| Property | Purpose | Example |
|----------|---------|---------|
| `PackageId` | Unique package identifier on nuget.org | `MyCompany.Widgets` |
| `Version` | SemVer 2.0 version | `1.2.3-beta.1` |
| `Authors` | Comma-separated author names | `Jane Doe, My Company` |
| `Description` | Package description for nuget.org | `Fluent widget management library` |
| `PackageTags` | Semicolon-separated search tags | `widgets;fluent;dotnet` |
| `PackageLicenseExpression` | SPDX license identifier | `MIT`, `Apache-2.0` |
| `PackageLicenseFile` | License file (alternative to expression) | `LICENSE.txt` |
| `PackageReadmeFile` | Markdown readme displayed on nuget.org | `README.md` |
| `PackageIcon` | Package icon filename | `icon.png` |
| `PackageProjectUrl` | Project homepage URL | `https://github.com/mycompany/widgets` |
| `PackageReleaseNotes` | Release notes for this version | `Added widget caching support` |
| `Copyright` | Copyright statement | `Copyright 2024 My Company` |
| `RepositoryUrl` | Source repository URL | `https://github.com/mycompany/widgets` |
| `RepositoryType` | Repository type | `git` |
### Directory.Build.props for Shared Metadata
For multi-project repos, set common properties in `Directory.Build.props`:
```xml
My Company
MIT
https://github.com/mycompany/widgets
https://github.com/mycompany/widgets
git
Copyright 2024 My Company
```text
Individual `.csproj` files then only set package-specific properties (`PackageId`, `Description`, `PackageTags`).
---
## Source Generator NuGet Packaging
Source generators and analyzers require a specific NuGet package layout. The generator DLL must be placed in the `analyzers/dotnet/cs/` folder, not the `lib/` folder. For Roslyn source generator authoring (IIncrementalGenerator, syntax/semantic analysis), see [skill:dotnet-csharp-source-generators]. This section covers NuGet *packaging* of generators only.
### Project Setup for Source Generator Package
```xml
netstandard2.0
true
true
MyCompany.Generators
Source generators for widget auto-registration.
false
true
true
```text
### Adding Build Props/Targets
When a source generator needs to set MSBuild properties in consuming projects, use the `buildTransitive` folder:
```xml
true
```text
Include `buildTransitive` content in the package:
```xml
```text
### Multi-Target Analyzer Package (Analyzer + Library)
When shipping both an analyzer and a runtime library in the same package:
```xml
net8.0;netstandard2.0
MyCompany.Widgets
```text
### NuGet Package Folder Layout
```text
MyCompany.Generators.1.0.0.nupkg
analyzers/
dotnet/
cs/
MyCompany.Generators.dll <-- generator/analyzer assembly
buildTransitive/
MyCompany.Generators.props <-- auto-imported MSBuild props
MyCompany.Generators.targets <-- auto-imported MSBuild targets
lib/
netstandard2.0/
_._ <-- empty marker (no runtime lib)
```text
---
## Multi-TFM Packages
Multi-targeting produces a single NuGet package with assemblies for each target framework. Consumers automatically get the best-matching assembly.
### When to Multi-Target
| Scenario | Approach |
|----------|----------|
| Library works on net8.0 only | Single TFM: `net8.0` |
| Library needs netstandard2.0 + net8.0 APIs | Multi-TFM: `netstandard2.0;net8.0` |
| Library uses net9.0-specific APIs (e.g., `SearchValues`) | Multi-TFM with polyfills or conditional code |
| Library targets .NET Framework consumers | Include `net472` or `netstandard2.0` TFM |
### Multi-TFM Configuration
```xml
netstandard2.0;net8.0;net9.0
```json
### Conditional Compilation
```csharp
public static class StringExtensions
{
public static bool ContainsIgnoreCase(this string source, string value)
{
#if NET8_0_OR_GREATER
return source.Contains(value, StringComparison.OrdinalIgnoreCase);
#else
return source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
#endif
}
}
```text
### NuGet Package Folder Layout (Multi-TFM)
```text
MyCompany.Widgets.1.0.0.nupkg
lib/
netstandard2.0/
MyCompany.Widgets.dll
net8.0/
MyCompany.Widgets.dll
net9.0/
MyCompany.Widgets.dll
```text
---
## Symbol Packages and Deterministic Builds
Symbol packages (`.snupkg`) enable source-level debugging for package consumers via the NuGet symbol server.
### Enabling Symbol Packages
```xml
true
snupkg
true
true
true
```text
The `snupkg` is pushed alongside the `nupkg` automatically when using `dotnet nuget push`:
```bash
# Push both .nupkg and .snupkg to nuget.org
dotnet nuget push "bin/Release/*.nupkg" \
--source https://api.nuget.org/v3/index.json \
--api-key "$NUGET_API_KEY"
```json
**SourceLink integration:** For source-level debugging with links to the actual source repository, configure SourceLink in your project. See [skill:dotnet-project-structure] for SourceLink setup -- do not duplicate that configuration here.
### Embedded PDB Alternative
For packages where a separate symbol package is undesirable:
```xml
embedded
```xml
This embeds the PDB directly in the assembly DLL. The tradeoff is larger package size but simpler distribution.
---
## Package Signing
NuGet supports author signing (proving package origin) and repository signing (proving it came from a specific feed).
### Author Signing with a Certificate
```bash
# Sign a package with a PFX certificate
dotnet nuget sign "MyCompany.Widgets.1.0.0.nupkg" \
--certificate-path ./signing-cert.pfx \
--certificate-password "$CERT_PASSWORD" \
--timestamper http://timestamp.digicert.com
# Sign with a certificate from the certificate store (Windows)
dotnet nuget sign "MyCompany.Widgets.1.0.0.nupkg" \
--certificate-fingerprint "ABC123..." \
--timestamper http://timestamp.digicert.com
```text
### Certificate Requirements
| Requirement | Detail |
|-------------|--------|
| Key usage | Code signing (1.3.6.1.5.5.7.3.3) |
| Algorithm | RSA 2048-bit minimum |
| Timestamping | Required for long-term validity |
| Trusted CA | DigiCert, Sectigo, or other trusted CA for nuget.org |
| Self-signed | Accepted for private feeds; rejected by nuget.org |
### Repository Signing
Repository signing is applied by feed operators (e.g., nuget.org signs all packages). Package authors do not need to configure repository signing -- it is applied automatically by the feed infrastructure.
### Verifying Package Signatures
```bash
# Verify a signed package
dotnet nuget verify "MyCompany.Widgets.1.0.0.nupkg"
# Verify with verbose output
dotnet nuget verify "MyCompany.Widgets.1.0.0.nupkg" --verbosity detailed
```text
---
## Package Validation
Package validation catches API breaks, invalid package layouts, and compatibility issues before publishing.
### Built-in Pack Validation
```xml
true
```text
This validates:
- All TFMs have compatible API surface
- No accidental API removals between package versions
- Package layout follows NuGet conventions
### API Compatibility with Baseline Version
Compare the current package against a previously published baseline version to detect breaking changes:
```xml
true
1.0.0
```text
### Microsoft.DotNet.ApiCompat.Task
For advanced API compatibility checking across assemblies:
```xml
true
true
```text
### Suppressing Known Breaks
When intentional API changes are made, generate and commit a suppression file:
```bash
# Generate suppression file for known breaks
dotnet pack /p:GenerateCompatibilitySuppressionFile=true
```bash
This creates `CompatibilitySuppressions.xml`:
```xml
CP0002
M:MyCompany.Widgets.Widget.OldMethod
lib/net8.0/MyCompany.Widgets.dll
lib/net8.0/MyCompany.Widgets.dll
```text
Reference the suppression file:
```xml
```xml
---
## NuGet Versioning Strategies
### SemVer 2.0 for NuGet
NuGet follows Semantic Versioning 2.0:
| Version | Meaning |
|---------|---------|
| `1.0.0` | Stable release |
| `1.0.1` | Patch (bug fixes, no API changes) |
| `1.1.0` | Minor (new features, backward compatible) |
| `2.0.0` | Major (breaking changes) |
| `1.0.0-alpha.1` | Pre-release alpha |
| `1.0.0-beta.1` | Pre-release beta |
| `1.0.0-rc.1` | Release candidate |
### Pre-release Suffixes
```xml
1.2.3
1.2.3-beta.1
```text
### NBGV Integration
Nerdbank.GitVersioning (NBGV) calculates versions from git history. For NBGV setup and `version.json` configuration, see [skill:dotnet-release-management]. This skill covers how NBGV-generated versions interact with NuGet packaging:
```xml
```text
NBGV produces versions like `1.2.42-beta+abcdef` where:
- `1.2` comes from `version.json`
- `42` is git commit height
- `-beta` is the pre-release suffix from `version.json`
- `+abcdef` is the git commit hash (build metadata, ignored by NuGet resolution)
### Version Properties Reference
| Property | Purpose | Set By |
|----------|---------|--------|
| `Version` | Full SemVer version (drives PackageVersion) | Manual or NBGV |
| `PackageVersion` | NuGet package version (defaults to Version) | Manual or NBGV |
| `AssemblyVersion` | CLR assembly version | Manual or NBGV |
| `FileVersion` | Windows file version | Manual or NBGV |
| `InformationalVersion` | Full version string with metadata | Manual or NBGV |
---
## Packing and Local Testing
### Building the Package
```bash
# Pack in Release configuration
dotnet pack --configuration Release
# Pack with specific version override
dotnet pack --configuration Release /p:Version=1.2.3-beta.1
# Output to specific directory
dotnet pack --configuration Release --output ./artifacts
```text
### Local Feed Testing
Test a package locally before publishing:
```bash
# Create a local feed directory
mkdir -p ~/local-nuget-feed
# Add the package to the local feed
dotnet nuget push "bin/Release/MyCompany.Widgets.1.0.0.nupkg" \
--source ~/local-nuget-feed
# In the consuming project, add the local feed
dotnet nuget add source ~/local-nuget-feed --name LocalFeed
```text
### Package Content Inspection
```bash
# List package contents (nupkg is a zip file)
unzip -l MyCompany.Widgets.1.0.0.nupkg
# Verify analyzer placement
unzip -l MyCompany.Generators.1.0.0.nupkg | grep analyzers/
```text
---
## Agent Gotchas
1. **Do not set both `PackageLicenseExpression` and `PackageLicenseFile`** -- they are mutually exclusive. Use `PackageLicenseExpression` for standard SPDX identifiers, `PackageLicenseFile` for custom licenses only.
1. **Source generators MUST target `netstandard2.0`** -- the Roslyn host requires this. Do not multi-target generators themselves; multi-target the runtime library that references the generator project.
1. **Do not set `IncludeBuildOutput` to `false` on library projects** -- only on pure analyzer/generator projects that should not contribute runtime assemblies.
1. **`buildTransitive` vs `build` folder** -- use `buildTransitive` for props/targets that should flow through transitive `PackageReference` dependencies. The `build` folder only affects direct consumers.
1. **Package validation suppression uses `ApiCompatSuppressionFile` with `CompatibilitySuppressions.xml`** -- not a `PackageValidationSuppression` MSBuild item. Generate the file with `/p:GenerateCompatibilitySuppressionFile=true`.
1. **SDK-style projects auto-include all `*.cs` files** -- adding TFM-conditional `Compile Include` without a preceding `Compile Remove` causes NETSDK1022 duplicate items.
1. **Never hardcode API keys in CLI examples** -- always use environment variable placeholders (`$NUGET_API_KEY`) with a note about CI secret storage.
1. **`ContinuousIntegrationBuild` must be conditional on CI** -- setting it unconditionally breaks local debugging by making PDBs non-reproducible with local file paths.
Project
Sdk
"Microsoft.NET.Sdk"
<PropertyGroup>
<TargetFramework>
</TargetFramework>
<PackageId>
</PackageId>
<Version>
</Version>
<Authors>
</Authors>
<Description>
</Description>
<PackageTags>
</PackageTags>
<PackageLicenseExpression>
</PackageLicenseExpression>
<PackageProjectUrl>
</PackageProjectUrl>
<RepositoryUrl>
</RepositoryUrl>
<RepositoryType>
</RepositoryType>
<!-- README displayed on nuget.org package page -->