ALWAYS follow these instructions first and only fallback to additional search and context gathering if the information here is incomplete or found to be in error.
- Review the
CONTRIBUTING.mdfile for instructions to build and test the software. - Run the
.github/Prime-ForCopilot.ps1script (once) before running anydotnetormsbuildcommands. If you see any build errors about not finding git objects or a shallow clone, it may be time to run this script again.
CRITICAL: Set the NBGV_GitEngine environment variable to Disabled before running ANY dotnet or msbuild commands.
export NBGV_GitEngine=DisabledSetup dependencies (takes ~2-3 seconds):
./init.ps1 -UpgradePrerequisites -NoNuGetCredProviderBuild the repository (takes 7-76 seconds depending on cache - do not cancel unless it exceeds 10-15 minutes, set timeout to 10-15 minutes):
dotnet build tools/dirs.proj -t:build,pack --no-restore -c ReleaseRun tests (takes ~25 seconds - NEVER CANCEL, set timeout to 5-10 minutes):
dotnet test --no-build -c Release -- --filter-not-trait "TestCategory=FailsInCloudTest"Verify code formatting (takes ~71 seconds - NEVER CANCEL, set timeout to 90+ minutes):
dotnet format --verify-no-changes --no-restoreBuild documentation (takes ~19 seconds):
DocFx=true dotnet docfx docfx/docfx.json --warningsAsErrors --disableGitFeaturesNEVER CANCEL: Code formatting verification takes approximately 71 seconds. This is normal and expected.
ALWAYS test functionality after making changes by running validation scenarios:
Test AOT Native Console sample:
cd test/AotNativeConsole
dotnet run --no-build -c ReleaseExpected output: JSON data followed by tree structure with fruits and seeds, ending with "Success".
Test ASP.NET MVC integration:
cd samples/AspNetMvc
dotnet run --no-build -c ReleaseShould start web server without errors (web UI testing limited in this environment).
- Establish a BenchmarkDotNet baseline before changing a hot path. For primitive integer encoding and decoding, run:
dotnet run --project test/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter "*IntegerPrimitives*" --job short - Keep benchmark input distributions explicit and reproducible.
Small,Mixed, andLargeinteger datasets exercise distinct MessagePack encodings and branch-prediction behavior; do not replace them with a single representative input. - For branch-sensitive work, use sufficiently large randomized datasets so a branch predictor cannot learn a short repeating sequence. Preserve the fixed random seed unless intentionally changing the workload.
- Review allocation, generated assembly, branch instructions, and branch mispredictions alongside elapsed time. Hardware counters require an elevated Windows process; an unavailable counter is not evidence of zero misses.
- Benchmark changes measure behavior; they do not prove correctness. Verify all MessagePack encoding boundaries and error behavior with the relevant tests before accepting an optimization.
- Prefer narrowly targeted candidates and retain a simple, verified baseline until benchmark results and generated assembly demonstrate a repeatable improvement for the intended distributions.
Nerdbank.MessagePack- Main MessagePack serialization libraryNerdbank.MessagePack.SignalR- SignalR integrationNerdbank.MessagePack.AspNetCoreMvcFormatter- ASP.NET Core MVC formatterNerdbank.MessagePack.Analyzers- Roslyn analyzers and code fixes
- Each shipping project has a corresponding
.Testsproject AotNativeConsole- NativeAOT compatibility validationBenchmarks- Performance benchmarks
AspNetMvc- ASP.NET Core MVC integration exampleSignalR- SignalR integration examplecsandfs- C# and F# usage examples
- Design APIs to be highly testable, and all functionality should be tested.
- Avoid introducing binary breaking changes in public APIs of projects under
srcunless their project files haveIsPackableset tofalse.
IMPORTANT: This repository uses Microsoft.Testing.Platform (MTP v2) with xunit v3. Traditional --filter syntax does NOT work. Use the options below instead.
- There should generally be one test project (under the
testdirectory) per shipping project (under thesrcdirectory). Test projects are named after the project being tested with a.Testssuffix. - Tests use xunit v3 with Microsoft.Testing.Platform (MTP v2). Traditional VSTest
--filtersyntax does NOT work. - Some tests are known to be unstable. When running tests, you should skip the unstable ones by using
-- --filter-not-trait "TestCategory=FailsInCloudTest".
Run all tests:
dotnet test --no-build -c ReleaseRun tests for a specific test project:
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c ReleaseRun a single test method:
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release -- --filter-method ClassName.MethodNameRun all tests in a test class:
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release -- --filter-class ClassNameRun tests with wildcard matching (supports wildcards at beginning and/or end):
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release -- --filter-method "*Pattern*"Run tests with a specific trait (equivalent to category filtering):
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release -- --filter-trait "TraitName=value"Exclude tests with a specific trait (skip unstable tests):
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release -- --filter-not-trait "TestCategory=FailsInCloudTest"Run tests for a specific framework only:
dotnet test --project test/Nerdbank.MessagePack.Tests/Nerdbank.MessagePack.Tests.csproj --no-build -c Release --framework net9.0List all available tests without running them:
cd test/Nerdbank.MessagePack.Tests
dotnet run --no-build -c Release --framework net9.0 -- --list-testsKey points about test filtering with MTP v2 / xunit v3:
- Options after
--are passed to the test runner, not todotnet test - Use
--filter-method,--filter-class,--filter-namespacefor simple filtering - Use
--filter-traitand--filter-not-traitfor trait-based filtering (replaces--filter "TestCategory=...") - Traditional VSTest
--filterexpressions do NOT work - Wildcards
*are supported at the beginning and/or end of filter values - Multiple simple filters of the same type use OR logic, different types combine with AND
- See
--helpfor query filter language for advanced scenarios
- Honor StyleCop rules and fix any reported build warnings after getting tests to pass.
- In C# files, use namespace statements instead of namespace blocks for all new files.
- Add API doc comments to all new public and internal members.
- Always run
dotnet format --verify-no-changes --no-restorebefore committing changes or CI will fail.
- When writing DocFX documentation (
.mdfiles in thedocfxdirectory), use<xref:symbolname>syntax for cross-references to types and members instead of@symbolnamesyntax.- Example: Use
<xref:Nerdbank.MessagePack.ConverterContext>instead of@Nerdbank.MessagePack.ConverterContext - This ensures proper linking and IDE support in the generated documentation.
- Example: Use
- Code samples should be placed in the
samples/csdirectory with region tags and referenced from documentation using[!code-csharp[](path#region)]syntax.- This keeps samples compilable and tested as part of the build.
- Build:
dotnet build tools/dirs.proj -t:build,pack --no-restore -c Release(NEVER CANCEL - 7-76s) - Test:
dotnet test --no-build -c Release -- --filter-not-trait "TestCategory=FailsInCloudTest"(25s) - Format:
dotnet format --verify-no-changes --no-restore(NEVER CANCEL - 71s) - Validate: Run AOT console sample for functionality verification
cd docfx
dotnet docfx --serve
# Make changes, then rebuild with:
dotnet docfx- Build fails: Ensure
NBGV_GitEngine=Disabledis set - Long restore times: Use
./init.ps1to bootstrap dependencies first - Test instability: Always use
-- --filter-not-trait "TestCategory=FailsInCloudTest" - Format failures: Run
dotnet format(without--verify-no-changes) to fix automatically
- Dependency setup: 2-3 seconds
- Full build: 7-76 seconds (fast with cache, slower on first build) (NEVER CANCEL - use 120+ minute timeouts)
- Test suite: ~25 seconds (NEVER CANCEL - use 60+ minute timeouts)
- Format verification: ~71 seconds (NEVER CANCEL - use 90+ minute timeouts)
- Documentation build: ~19 seconds
NEVER CANCEL long-running commands - these timing expectations are normal for this repository.