- Add Microsoft.Extensions.Logging + Serilog to NatsServer and NatsClient - Convert all test assertions from xUnit Assert to Shouldly - Add NSubstitute package for future mocking needs - Introduce Central Package Management via Directory.Packages.props - Add documentation_rules.md with style guide, generation/update rules, component map - Generate 10 documentation files across 5 component folders (GettingStarted, Protocol, Subscriptions, Server, Configuration/Operations) - Update CLAUDE.md with logging, testing, porting, agent model, CPM, and documentation guidance
5.3 KiB
Setup
This guide covers prerequisites, building, running, and testing the NATS .NET server.
Prerequisites
.NET 10 SDK
The project targets net10.0 with LangVersion preview (configured in Directory.Build.props). Install the .NET 10 preview SDK from https://dotnet.microsoft.com/download.
Verify your installation:
dotnet --version
# Expected: 10.0.x
Go Toolchain (optional)
The Go toolchain is only needed if you want to run the reference server from golang/nats-server/ or execute Go test suites for cross-validation. It is not required for building or testing the .NET port.
go version
# Expected: go1.22 or later
Building
The solution file uses the .slnx format (not .sln). Pass it explicitly if your tooling requires it.
# Build all projects
dotnet build
# Clean and rebuild
dotnet clean && dotnet build
The solution contains three projects:
| Project | Path |
|---|---|
NATS.Server |
src/NATS.Server/ |
NATS.Server.Host |
src/NATS.Server.Host/ |
NATS.Server.Tests |
tests/NATS.Server.Tests/ |
All projects share settings from Directory.Build.props: net10.0 target framework, nullable reference types enabled, warnings treated as errors.
Running
The server executable is NATS.Server.Host. With no arguments it binds to 0.0.0.0:4222.
dotnet run --project src/NATS.Server.Host
CLI Arguments
| Flag | Alias | Type | Default | Description |
|---|---|---|---|---|
-p |
--port |
int |
4222 |
TCP port to listen on |
-a |
--addr |
string |
0.0.0.0 |
Bind address |
-n |
--name |
string |
nats-dotnet-<hostname> |
Server name reported in INFO |
# Custom port
dotnet run --project src/NATS.Server.Host -- -p 14222
# Custom address and name
dotnet run --project src/NATS.Server.Host -- -a 127.0.0.1 -p 4222 -n dev-server
The -- separator is required to pass arguments through dotnet run to the application.
Startup log output (Serilog console sink):
[12:00:00 INF] Listening on 0.0.0.0:4222
Testing
# Run all tests
dotnet test
# Run tests with verbose output
dotnet test -v normal
# Run a single test project
dotnet test tests/NATS.Server.Tests
# Run a specific test by name
dotnet test tests/NATS.Server.Tests --filter "FullyQualifiedName~SubListTests"
Test Stack
| Package | Version | Purpose |
|---|---|---|
xunit |
2.9.3 | Test framework |
xunit.runner.visualstudio |
3.1.4 | VS/Rider test runner integration |
Shouldly |
4.3.0 | Assertion library |
NSubstitute |
5.3.0 | Mocking |
NATS.Client.Core |
2.7.2 | Official NATS .NET client for integration tests |
coverlet.collector |
6.0.4 | Code coverage |
Do not use FluentAssertions or Moq — the project uses Shouldly and NSubstitute exclusively.
Test Files
| File | Covers |
|---|---|
ParserTests.cs |
NatsParser.TryParse for each command type |
SubjectMatchTests.cs |
SubjectMatch validation and wildcard matching |
SubListTests.cs |
SubList trie insert, remove, match, and cache behaviour |
ClientTests.cs |
NatsClient command dispatch and subscription tracking |
ServerTests.cs |
NatsServer pub/sub, wildcards, queue groups |
IntegrationTests.cs |
End-to-end tests using NATS.Client.Core against a live server |
NuGet: Central Package Management
Package versions are defined centrally in Directory.Packages.props. Individual .csproj files reference packages without a Version attribute:
<!-- Directory.Packages.props -->
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<!-- NATS.Server.Tests.csproj -->
<PackageReference Include="Shouldly" />
<PackageReference Include="NSubstitute" />
To add a new dependency: add a <PackageVersion> entry in Directory.Packages.props, then add a <PackageReference> (without Version) in the relevant .csproj.
Logging
The host configures Serilog via Microsoft.Extensions.Logging in Program.cs:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
using var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(Log.Logger);
var server = new NatsServer(options, loggerFactory);
NatsServer and NatsClient receive ILoggerFactory and ILogger respectively via constructor injection. The core library (NATS.Server) depends only on Microsoft.Extensions.Logging.Abstractions — it has no direct Serilog dependency. The Serilog packages are wired in NATS.Server.Host.
Per-client loggers are created with a scoped category name that includes the client ID:
var clientLogger = _loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]");
To adjust log levels at runtime, modify the LoggerConfiguration in Program.cs.