Demarbit.Shared.Api
1.0.4
dotnet add package Demarbit.Shared.Api --version 1.0.4
NuGet\Install-Package Demarbit.Shared.Api -Version 1.0.4
<PackageReference Include="Demarbit.Shared.Api" Version="1.0.4" />
<PackageVersion Include="Demarbit.Shared.Api" Version="1.0.4" />
<PackageReference Include="Demarbit.Shared.Api" />
paket add Demarbit.Shared.Api --version 1.0.4
#r "nuget: Demarbit.Shared.Api, 1.0.4"
#:package Demarbit.Shared.Api@1.0.4
#addin nuget:?package=Demarbit.Shared.Api&version=1.0.4
#tool nuget:?package=Demarbit.Shared.Api&version=1.0.4
Demarbit.Shared.Api
Shared ASP.NET Core API library for DDD / Clean Architecture projects. Provides a configurable ProblemDetails exception filter, correlation ID middleware, security headers middleware, session resolution middleware, OpenAPI transformers for Optional<T>, and DI/pipeline wiring.
Logging provider and auth strategy agnostic — consumers configure their own Serilog/NLog, JWT Bearer/OAuth/API keys, CORS, rate limiting, and OpenAPI setup.
Installation
dotnet add package Demarbit.Shared.Api
The consumer adds their own project-specific packages:
# Authentication (pick one)
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
# Logging (recommended, not required)
dotnet add package Serilog.AspNetCore
# OpenAPI (if used)
dotnet add package Microsoft.AspNetCore.OpenApi
Dependencies
| Package | Purpose |
|---|---|
Demarbit.Shared.Domain |
DomainException for exception mapping |
Demarbit.Shared.Application |
AppException hierarchy, OptionalJsonConverterFactory, ISessionContext |
Microsoft.AspNetCore.App |
Framework reference: ProblemDetails, IExceptionFilter, middleware, health checks, JSON |
Microsoft.AspNetCore.OpenApi |
IOpenApiDocumentTransformer for Optional<T> and content type transformers |
Quick Start
1. Register Services
using Demarbit.Shared.Api.Extensions;
// Basic setup with defaults:
services.AddSharedApi();
// Or with customizations:
services.AddSharedApi(options =>
{
// Disable HSTS for local development
options.SecurityHeaders.StrictTransportSecurity = null;
// Add project-specific exception mappings
options.ExceptionMapping.Map<PaymentDeclinedException>(
402, "Payment Required", "https://httpstatuses.io/402");
});
This registers:
ProblemDetailsExceptionFilter(global exception → ProblemDetails)ICorrelationIdAccessor(access correlation ID from any service)OptionalJsonConverterFactory(PATCH semantics JSON support)- Liveness health check (
"self")
2. Configure the Pipeline
using Demarbit.Shared.Api.Extensions;
using Demarbit.Shared.Api.Middleware;
var app = builder.Build();
// Shared middleware (security headers → correlation ID → error handler):
app.UseSharedApi();
// Project-specific middleware:
app.UseSerilogRequestLogging(); // consumer adds Serilog
app.UseCors(); // consumer configures CORS
app.UseRateLimiter(); // consumer configures rate limiting
app.UseAuthentication(); // consumer configures auth
app.UseAuthorization();
app.UseMiddleware<SessionResolutionMiddleware>();
// Endpoints:
app.MapControllers();
app.MapSharedHealthChecks(); // /healthz (live) + /readyz (ready)
await app.RunAsync();
3. Implement Session Resolution
using Demarbit.Shared.Api.Contracts;
// Your project's implementation:
internal sealed class AppSessionResolver(IUserProfileRepository userRepo) : ISessionResolver
{
public async Task ResolveAsync(
HttpContext context,
ISessionContext session,
ClaimsPrincipal user)
{
var authIdClaim = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (Guid.TryParse(authIdClaim, out var authId))
{
var profile = await userRepo.FindByAuthIdAsync(authId);
if (profile is not null)
{
session.SetUserId(profile.Id);
session.SetLocale(profile.Locale);
session.SetTimeZone(profile.TimeZone);
}
}
}
}
// Register in DI:
services.AddScoped<ISessionResolver, AppSessionResolver>();
If no ISessionResolver is registered, the middleware is a no-op.
4. Standard Program.cs
using Serilog;
using Demarbit.Shared.Api.Extensions;
using Demarbit.Shared.Api.Middleware;
using MyApp.Application.DependencyInjections;
using MyApp.Infrastructure.DependencyInjections;
var builder = WebApplication.CreateBuilder(args);
// Logging (consumer's choice — Serilog recommended)
builder.Host.UseSerilog((ctx, services, cfg) =>
{
cfg.ReadFrom.Configuration(ctx.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext();
});
// Request size limits
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 MB
});
// Layer registration
builder.Services.AddApplication();
builder.Services.AddInfrastructure(builder.Configuration);
builder.Services.AddSharedApi();
// Auth (consumer's choice)
builder.Services.AddAuthentication(/* ... */).AddJwtBearer(/* ... */);
builder.Services.AddAuthorization();
// CORS (consumer's choice)
builder.Services.AddCors(/* ... */);
// Session resolver
builder.Services.AddScoped<ISessionResolver, AppSessionResolver>();
var app = builder.Build();
// Pipeline
app.UseSharedApi();
app.UseSerilogRequestLogging();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<SessionResolutionMiddleware>();
if (app.Environment.IsDevelopment())
app.MapOpenApi();
app.MapControllers();
app.MapSharedHealthChecks();
if (!app.Environment.IsEnvironment("Testing"))
await app.Services.BootstrapDatabaseAsync<AppDbContext>();
await app.RunAsync();
namespace MyApp.Api
{
public partial class Program { }
}
5. JWT Authentication (Recommended Pattern)
The shared library provides JwtOptions for configuration binding but does not register auth — that's project-specific:
using Demarbit.Shared.Api.Configuration;
var jwtOptions = builder.Configuration.GetSection(JwtOptions.SectionName).Get<JwtOptions>()
?? throw new ConfigurationException(JwtOptions.SectionName);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(bearer =>
{
bearer.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidAudience = jwtOptions.Audience,
ValidIssuer = jwtOptions.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtOptions.Secret)),
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddAuthorization();
6. OpenAPI with Shared Transformers
using Demarbit.Shared.Api.OpenApi.Transformers;
services.AddOpenApi("v1", opts =>
{
// Shared transformers from the library:
opts.AddDocumentTransformer<OptionalSchemaDocumentTransformer>();
opts.AddDocumentTransformer<RemoveUnnecessaryContentTypesTransformer>();
// Project-specific customizations:
opts.AddDocumentTransformer((document, context, ct) =>
{
document.Info.Title = "My API";
document.Info.Description = "My API description.";
return Task.CompletedTask;
});
});
7. Health Checks
using Demarbit.Shared.Api.Extensions;
using Demarbit.Shared.Infrastructure.Extensions;
// Readiness checks (consumer adds their own):
builder.Services.AddHealthChecks()
.AddDbContextHealthCheck<AppDbContext>(tags: ["ready"])
.AddNpgSql(connectionString, name: "postgres", tags: ["ready"]);
// Endpoints (in pipeline):
app.MapSharedHealthChecks();
// Maps:
// /healthz → liveness (checks tagged "live" — self-check always healthy)
// /readyz → readiness (checks tagged "ready" — database, etc.)
Exception → ProblemDetails Mapping
Default mappings (most specific first):
| Exception | Status | Title |
|---|---|---|
ValidationFailedException |
400 | Validation failed |
NotFoundException |
404 | Not found |
ForbiddenException |
403 | Forbidden |
ConflictException |
409 | Conflict |
AppException (catch-all) |
400 | Application error |
DomainException |
422 | Domain rule violation |
Unmatched Exception |
500 | Unexpected error |
All responses include traceId and correlationId extensions. ValidationFailedException responses include an errors extension with structured validation errors. Development mode includes stack traces and inner exception details.
What's Included
| Type | Purpose |
|---|---|
ProblemDetailsExceptionFilter |
Configurable exception → ProblemDetails with trace/correlation IDs |
CorrelationIdMiddleware |
Reads/generates X-Correlation-ID, stores for downstream access |
SecurityHeadersMiddleware |
Configurable security headers with sensible defaults |
SessionResolutionMiddleware |
Delegates to consumer's ISessionResolver |
ISessionResolver |
Consumer implements user identity resolution |
ICorrelationIdAccessor |
Access correlation ID from any scoped service |
SharedApiOptions |
Top-level options (exception mapping + security headers) |
SecurityHeadersOptions |
Individual header values, nullable to disable |
ExceptionProblemDetailsMap |
Configurable exception type → status/title/URI mapping |
ProblemDetailsDescriptor |
Resolved mapping result |
JwtOptions |
Universal JWT configuration (audience, issuer, secret) |
HttpHeaders |
Constants for header names (X-Correlation-ID, etc.) |
OpenApiGroupTitleAttribute |
Group title metadata for controllers |
OptionalSchemaDocumentTransformer |
Fixes Optional<T> OpenAPI schemas |
RemoveUnnecessaryContentTypesTransformer |
Strips non-JSON content types |
ServiceCollectionExtensions.AddSharedApi() |
DI registration |
WebApplicationExtensions.UseSharedApi() |
Middleware pipeline |
WebApplicationExtensions.MapSharedHealthChecks() |
/healthz + /readyz endpoints |
Package Family
Demarbit.Shared.Domain ← zero deps
↑
Demarbit.Shared.Application ← Domain + M.E.DI + M.E.Logging
↑ ↑
Demarbit.Shared.Infrastructure Demarbit.Shared.Api
↑ (EF Core) ↑ (ASP.NET Core)
| |
+--------- [Consumer Project] --------+
adds provider NuGets, auth, Serilog, CORS, etc.
Note: Demarbit.Shared.Api does not depend on Demarbit.Shared.Infrastructure. This preserves the Clean Architecture dependency rule — the API layer knows nothing about EF Core or database concerns.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Demarbit.Shared.Application (>= 1.0.4)
- Demarbit.Shared.Domain (>= 1.0.4)
- Demarbit.Shared.Infrastructure (>= 1.0.4)
- Microsoft.AspNetCore.OpenApi (>= 10.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.4 | 92 | 2/20/2026 |