A production-ready .NET 8 service template with the complete JG .NET Library Collection pre-wired. Clone it, rename it, and start building your service. All the infrastructure code is already done.
Every JG library is integrated with sensible defaults and real examples:
- JG.ConfigKit — Multi-source configuration (appsettings, env vars, CLI args, user secrets)
- JG.ErrorKit — Typed errors with RFC 7807 Problem Details for APIs
- JG.LoggingKit — Structured logging with correlation IDs and JSON formatting
- JG.CacheKit — In-memory and distributed caching with stampede protection
- JG.RateLimiter — Token bucket and sliding window rate limiting
- JG.HealthKit — Kubernetes-ready liveness and readiness endpoints
- JG.AuthKit — JWT authentication with refresh tokens and RBAC
- JG.EventKit — In-process event bus for decoupled components
- JG.WorkerKit — Background job queue with cron scheduling
- JG.AuditKit — Immutable audit logging with optional hash chaining
Plus working examples: status endpoint, correlation ID middleware, startup event, scheduled cleanup job.
git clone https://github.com/jamesgober/dotnet-service-template.git my-service
cd my-service
dotnet run --project src/MyServiceThe service starts on http://localhost:5000. Test it:
curl http://localhost:5000/status- GET /status — Service info, version, uptime, environment
- CorrelationIdMiddleware — Tracks every request with
X-Correlation-ID
- ServiceStartedEvent — Published when the host starts, demonstrates event bus pattern
- CleanupJob — Placeholder for scheduled maintenance tasks
Working appsettings for development and production environments. Everything has sensible defaults that work out of the box.
The order matters. Each middleware wraps the next:
- Correlation ID — Tag every request first
- Error handling — Catch exceptions and convert to Problem Details
- Rate limiting — Reject excessive traffic early
- Authentication — Resolve JWT identity
- Authorization — Enforce permissions
- Health endpoints — Bypass auth for /health/live and /health/ready
- Application endpoints — Your API
This order ensures requests are tracked, failures are handled gracefully, and auth happens before business logic.
Create a file in src/MyService/Endpoints/:
public static class GreetingEndpoint
{
public static void Map(WebApplication app)
{
app.MapGet("/greet/{name}", (string name) =>
Results.Ok(new { Greeting = $"Hello, {name}!" }));
}
}Register in Program.cs:
GreetingEndpoint.Map(app);Create event and handler in src/MyService/Events/:
public sealed class OrderPlacedEvent
{
public required string OrderId { get; init; }
}
public sealed class OrderPlacedHandler
{
private readonly ILogger<OrderPlacedHandler> _logger;
public OrderPlacedHandler(ILogger<OrderPlacedHandler> logger) => _logger = logger;
public Task HandleAsync(OrderPlacedEvent @event, CancellationToken ct)
{
_logger.LogInformation("Order {OrderId} placed", @event.OrderId);
return Task.CompletedTask;
}
}Register in Program.cs:
builder.Services.AddSingleton<OrderPlacedHandler>();Publish from anywhere:
await eventBus.PublishAsync(new OrderPlacedEvent { OrderId = "12345" });Create a job in src/MyService/Jobs/:
public sealed class ReportGenerationJob
{
public async Task ExecuteAsync(CancellationToken ct)
{
// Generate reports
}
}Schedule in Program.cs:
builder.Services.AddScheduledJob<ReportGenerationJob>("0 2 * * *"); // Daily at 2 AMAll settings in appsettings.json. Override per environment with appsettings.{Environment}.json.
Service info:
"Service": {
"Name": "MyService",
"Version": "1.0.0"
}Logging:
"Logging": {
"Level": "Information",
"Format": "console"
}Cache:
"Cache": {
"DefaultTtlSeconds": 300,
"Provider": "memory"
}Switch to Redis in production: "Provider": "redis" (requires JG.CacheKit.Redis package).
Rate limiting:
"RateLimiting": {
"Global": {
"PermitsPerWindow": 100,
"WindowSeconds": 60
}
}Auth:
"Auth": {
"Issuer": "https://localhost",
"Audience": "myservice",
"SecretKey": "CHANGE-THIS-IN-PRODUCTION-minimum-32-chars!"
}Never commit real secrets. Use user secrets for dev, environment variables for prod.
Audit:
"Audit": {
"Enabled": true,
"HashChaining": true,
"Sink": "file",
"FilePath": "logs/audit.jsonl"
}# Restore dependencies
dotnet restore
# Build
dotnet build --configuration Release
# Run tests
dotnet test --configuration Release
# Run the service
dotnet run --project src/MyServiceAll JG packages are referenced as NuGet dependencies. If a package isn't published yet, its registration is commented out in Program.cs. Uncomment when available.
src/
├── MyService/
│ ├── Program.cs # Host builder, DI, middleware pipeline
│ ├── appsettings.json # Base configuration
│ ├── appsettings.Development.json # Dev overrides
│ ├── Endpoints/ # API endpoint handlers
│ ├── Events/ # Event definitions and handlers
│ ├── Jobs/ # Background job implementations
│ └── Middleware/ # Custom middleware
tests/
├── MyService.Tests/ # xUnit tests with WebApplicationFactory
docs/
├── API.md # Endpoint and configuration docs
- API Reference — Endpoints, middleware, configuration
- Changelog — Version history
Apache 2.0 — see LICENSE
James Gober — github.com/jamesgober