CoreSystem.Http.ProblemDetails
1.1.0
dotnet add package CoreSystem.Http.ProblemDetails --version 1.1.0
NuGet\Install-Package CoreSystem.Http.ProblemDetails -Version 1.1.0
<PackageReference Include="CoreSystem.Http.ProblemDetails" Version="1.1.0" />
<PackageVersion Include="CoreSystem.Http.ProblemDetails" Version="1.1.0" />
<PackageReference Include="CoreSystem.Http.ProblemDetails" />
paket add CoreSystem.Http.ProblemDetails --version 1.1.0
#r "nuget: CoreSystem.Http.ProblemDetails, 1.1.0"
#:package CoreSystem.Http.ProblemDetails@1.1.0
#addin nuget:?package=CoreSystem.Http.ProblemDetails&version=1.1.0
#tool nuget:?package=CoreSystem.Http.ProblemDetails&version=1.1.0
⚠️ CoreSystem.Http.ProblemDetails
Consistent RFC 9457 Problem Details for ASP.NET Core APIs.
CoreSystem.Http.ProblemDetails provides reusable exception-to-HTTP error handling for ASP.NET Core APIs on .NET 8, .NET 9 and .NET 10. It owns the HTTP mechanism while each application keeps its domain exceptions, business error codes, and mapping rules.
✨ Features
- ✅ RFC 9457
application/problem+jsonresponses - ✅ Application-owned exception mapping through
IExceptionProblemMapper - ✅ Standard
errorCodeandtraceIdextensions - ✅ W3C
Activity.Current.TraceIdwithHttpContext.TraceIdentifierfallback - ✅ Application-specific extensions through a callback
- ✅ Exception type and message exposed only in Development
- ✅ No dependency on domain, application, or idempotency packages
📦 Installation
dotnet add package CoreSystem.Http.ProblemDetails
🚀 Quick Start
Implement the mapper in the API or Infrastructure layer. Domain and Application projects do not need to reference this package.
using Core.Http.ProblemDetails;
using Core.Http.ProblemDetails.DependencyInjection;
using Microsoft.AspNetCore.Http;
public sealed class ApiExceptionProblemMapper : IExceptionProblemMapper
{
public ProblemDescriptor Map(Exception exception) => exception switch
{
OrderNotFoundException => new(
StatusCodes.Status404NotFound,
"ORDER_NOT_FOUND",
"Order not found",
"The requested order does not exist",
"urn:example:error:order-not-found"),
_ => new(
StatusCodes.Status500InternalServerError,
"INTERNAL_ERROR",
"Unexpected error",
"An unexpected error occurred")
};
}
Register Problem Details and the mapper-backed exception handler:
builder.Services.AddCoreProblemDetails();
builder.Services.AddCoreExceptionHandler<ApiExceptionProblemMapper>();
var app = builder.Build();
app.UseExceptionHandler();
AddCoreExceptionHandler<TMapper>() registers the concrete mapper as scoped
when it has not already been registered. Register any dependencies required by
the mapper in the usual way. The exception handler creates a scope for each
handled exception, so scoped mapper dependencies (such as a DbContext) are
resolved and disposed correctly.
🔌 Application Extensions
Applications can add fields without introducing domain dependencies into this
package. For example, an API that uses CoreSystem.Idempotency can expose the
key related to a fingerprint mismatch:
using Core.Idempotency.Exceptions;
builder.Services.AddCoreProblemDetails(options =>
{
options.CustomizeProblemDetails = (problem, context, exception) =>
{
if (exception is IdempotencyFingerprintMismatchException)
{
problem.Extensions["idempotencyKey"] =
context.Request.Headers["Idempotency-Key"].ToString();
}
};
});
📄 Response Contract
For an exception mapped to a conflict, the handler produces a response similar to the following:
{
"type": "urn:example:error:order-already-exists",
"title": "Order already exists",
"status": 409,
"detail": "An order with this identifier already exists",
"instance": "/orders/42",
"errorCode": "ORDER_ALREADY_EXISTS",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}
The handler provides status, title, detail, type, instance,
errorCode, and traceId. If the mapper does not specify a type, the handler
uses about:blank.
In Development, exceptionType and exceptionMessage are added. They are
omitted in every other environment.
🏗 Architecture
Domain / Application
│
▼
Application Exception Mapper
│
▼
IExceptionProblemMapper
│
▼
CoreExceptionHandler
│
▼
RFC 9457 Problem Details Response
The application owns the vocabulary of errors. CoreSystem owns only reusable HTTP infrastructure.
📖 Public API
| Type | Description |
|---|---|
ProblemDescriptor |
Domain-agnostic description of an HTTP problem. |
IExceptionProblemMapper |
Maps an exception to a ProblemDescriptor. |
AddCoreProblemDetails() |
Registers RFC 9457 serialization and customization. |
AddCoreExceptionHandler<TMapper>() |
Registers the mapper-backed exception handler. |
CoreProblemDetailsOptions |
Provides the CustomizeProblemDetails callback. |
📚 Documentation
The full documentation includes:
- Getting Started
- Exception Mapping
- Application Extensions
- Response Contract
- Development Diagnostics
- Best Practices
🤝 Contributing
Issues, discussions and pull requests are welcome.
📄 License
Released under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release with RFC 9457 Problem Details, exception mapping, trace identifiers, and extension callbacks.
1.1.0: Targets net8.0, net9.0 and net10.0 (previously net8.0 only). No public API or behavior change; the net9.0 and net10.0 assets are new, and the net8.0 assembly is unchanged. The nuspec no longer declares Microsoft.Extensions.DependencyInjection.Abstractions and Microsoft.Extensions.Options as package dependencies: both assemblies ship in the Microsoft.AspNetCore.App framework reference the package already carries, so consumers are unaffected.