RA.Utilities.Api
Version 10.4.0
IEndpointGroup.MapGroup and IEndpoint.MapEndpoint now receive the API version set as an optional second parameter, and the generated MapEndpoints method takes an optional ApiVersionSet? apiVersionSet = null that it forwards to every implementation — apply it with WithApiVersionSet to version whole groups or individual endpoints.
✨ New Features
ApiVersionSetthreading:app.MapEndpoints(apiVersionSet)forwards the version set to everyMapGroup(IEndpointRouteBuilder, ApiVersionSet?)andMapEndpoint(RouteGroupBuilder, ApiVersionSet?)implementation, matching the standardapp.MapGroup(...).WithApiVersionSet(apiVersionSet)pattern. The package now referencesAsp.Versioning.Http(10.x), which flows to consumers transitively; the parameter is optional, so unversioned APIs just callapp.MapEndpoints().
⚠️ Breaking Changes
IEndpointGroup/IEndpointsignatures:MapGroupandMapEndpointimplementations must declare the new optionalApiVersionSet? apiVersionSet = nullparameter (the interface declares it with a default value, but implementations must accept it). The generated registration code always passes the value.
Version 10.3.0
PaymentRequiredException is now mapped to the dedicated PaymentRequiredResponse (HTTP 402) instead of the generic ErrorResponse, and the exception handler classifies 402 and 429 throws as client errors.
✨ New Features
- HTTP 402 mapping:
ErrorResultResponse.Result(PaymentRequiredException)returns aResults.Jsonresult with status code 402, and the newErrorResultMapper.ToResponse(PaymentRequiredException)overload builds aPaymentRequiredResponsefrom the exception's code and message (resultstaysnull). Previously the exception fell through to theRaBaseExceptionarm and produced an HTTP 500ErrorResponse. RequiresRA.Utilities.Api.Response10.2.0,RA.Utilities.Core.Exceptions10.2.0, andRA.Utilities.Core.Constants10.1.1.
📝 Improvements
- Client-error logging:
GlobalExceptionHandlertreatsPaymentRequiredExceptionandTooManyRequestsExceptionas client errors, so both are logged atWarninginstead ofError.ServiceUnavailableException,GatewayTimeoutException, and otherRaBaseExceptiontypes remain atError.
Version 10.2.3
Maintenance release completing the internal migration to the RA.Utilities.Api.Response namespace and updating FluentValidation to 12.2.0. No public API or behavior changes.
📝 Improvements
- Namespace migration completed: the mapper helpers (
ErrorResultResponse,ErrorResultMapper,SuccessResult) andDefaultHeadersMiddlewarenow import the response models fromRA.Utilities.Api.Responseinstead of the transitionalRA.Utilities.Api.Resultsnamespace, and the verboseMicrosoft.AspNetCore.Http.Results.*qualifications are simplified toResults.*. Call sites are unaffected. - FluentValidation 12.1.1 → 12.2.0.
Version 10.2.2
The monolithic MiddlewareExtensions class is split back into one class per target type — ApplicationBuilderExtensions for the Use* methods and ServiceCollectionExtensions for the Add* methods — and every extension method is now declared with C# 14 extension members. Method names, signatures, and the namespace are unchanged.
⚠️ Breaking Changes
MiddlewareExtensionssplit intoApplicationBuilderExtensionsandServiceCollectionExtensions: theAdd*methods live inServiceCollectionExtensions(extension members onIServiceCollection), theUse*methods inApplicationBuilderExtensions(extension members onIApplicationBuilder). Call sites need no changes — extension methods resolve by target type — but code that references theMiddlewareExtensionsclass name directly (typeof(...), unit-test assertions, reflection) must be updated.
- var t = typeof(MiddlewareExtensions);
+ var s = typeof(ServiceCollectionExtensions); // Add* methods
+ var a = typeof(ApplicationBuilderExtensions); // Use* methods
📝 Improvements
-
C# 14 extension members:
ApplicationBuilderExtensions,ServiceCollectionExtensions, andValidationExtensionsnow declare their methods insideextension(...)blocks onIApplicationBuilder,IServiceCollection, andRouteHandlerBuilderrespectively. The generated extension methods have identical names and signatures, so the refactor is source-compatible for all callers. -
ValidationExtensionsrefactored:Validate<TModel>()is now a member of anextension(RouteHandlerBuilder builder)block. The calling syntax is unchanged:app.MapPost(...).Validate<CreateRequest>(). -
Response model dependency updated: the package now references
RA.Utilities.Api.Response10.1.0, whose models moved from theRA.Utilities.Api.Resultsnamespace toRA.Utilities.Api.Response. The mapper and header middleware use the new namespace. Consumer code only needs ausingupdate if it references the response models directly. -
The split restores the pre-10.1.0 organization (one extension class per target type) while keeping every method name, so upgrading from 10.2.1 requires no call-site changes.
Version 10.2.1
LoggingMiddleware response logging behavior is now explicit, and the shared HTTP log templates drop their correlation properties in favor of the log scope.
The request-context middleware is renamed RequestContextLoggingMiddleware → ContextLoggingMiddleware, and its pipeline extension method was renamed with it: UseRequestContextLoggingMiddleware() → UseContextLoggingMiddleware(). The DI registration method AddRequestContextLoggingMiddleware() keeps its name.
⚠️ Breaking Changes
-
Log templates no longer carry
RequestId/TraceIdentifier(viaRA.Utilities.Logging.Shared10.0.2): structured request/response logs produced byLoggingMiddlewareno longer contain these properties. Correlation continues to work through the log scope (LoggingConstants.XRequestId) the middleware creates for every request — no code changes needed unless you query those properties directly. -
RequestContextLoggingMiddlewarerenamed toContextLoggingMiddleware: code that references the middleware type directly — customUseMiddleware<T>()/AddTransient<T>()calls, unit tests,typeof(...)— must use the new name. The pipeline extension method was renamed too (app.UseRequestContextLoggingMiddleware()→app.UseContextLoggingMiddleware()); the DI registration methodAddRequestContextLoggingMiddleware()is unchanged.
- app.UseMiddleware<RequestContextLoggingMiddleware>();
- services.AddTransient<RequestContextLoggingMiddleware>();
+ app.UseMiddleware<ContextLoggingMiddleware>();
+ services.AddTransient<ContextLoggingMiddleware>();
// The pipeline helper was renamed as well:
- app.UseRequestContextLoggingMiddleware();
+ app.UseContextLoggingMiddleware();
// The DI helper keeps its name:
builder.Services.AddRequestContextLoggingMiddleware();
📝 Improvements
- Response log level clarified: the response log (
HTTP Response: {@ResponseLog}) is written atLogLevel.Warning; the request log remains atLogLevel.Information, and both are skipped whenInformationis not enabled.
private async Task LogResponseAsync(HttpContext context, MemoryStream responseBody, TimeSpan duration)
{
if (!_logger.IsEnabled(LogLevel.Information))
return;
// ...
_logger.LogWarning("HTTP Response: {@ResponseLog}", responseLog);
}
- Dedicated slow-call warning: when the total elapsed time exceeds
WarningThresholdMilliseconds, an additionalWarningentry is written alongside the response log.
+ if (LogWarning(stopwatch.Elapsed))
+ _logger.LogWarning("HTTP call to {Method} {Url} took too long ({ElapsedMilliseconds} ms)", ...);
- The shorter name better reflects the middleware's single responsibility: enriching the log scope with the
X-Request-Idcorrelation ID for every request.
Version 10.1.0
This release replaces the reflection-based endpoint registration with a compile-time, source-generated pipeline. Endpoints are now discovered by the RA.Utilities.Api.Generators analyzer (shipped inside the package) and registered without reflection, DI scanning, or manual registration lists.
⚠️ Breaking Changes
IEndpointredesigned: The instance-basedIEndpointinterface (void MapEndpoint(IEndpointRouteBuilder)) has been replaced by a static-abstract contract:static abstract string GroupName { get; }andstatic abstract void MapEndpoint(RouteGroupBuilder group). Endpoint classes are now referenced statically by the generated registration code and no longer need to be instantiable.EndpointExtensionsremoved: The reflection-basedAddEndpoints/MapEndpointsextension methods have been removed. Theapp.MapEndpoints()call now maps everyIEndpointGroupandIEndpointimplementation discovered at compile time by the source generator.- Middleware extension classes consolidated into
MiddlewareExtensions:DefaultHeadersMiddlewareExtensions,ExceptionHandlingExtensions,LoggingMiddlewareExtensions, andRequestContextLoggingMiddlewareExtensionshave been merged into a singleMiddlewareExtensionsclass (same namespace,RA.Utilities.Api.Extensions). All extension methods keep their names, so no call-site changes are required unless code referenced the old class names directly.
✨ New Features
IEndpointGroupinterface: Defines a shared route group (static abstract string GroupName,static abstract RouteGroupBuilder MapGroup(IEndpointRouteBuilder app)) that endpoints map into. Every group is created exactly once, before any endpoint is mapped.- Compile-time endpoint registration: A new Roslyn incremental source generator (
RA.Utilities.Api.Generators) scans the consuming assembly forIEndpointGroupandIEndpointimplementations and emits theMapEndpoints()extension method (RA.Utilities.Api.Extensions.HttpEndpointServiceCollectionExtensions). No reflection, no runtime instantiation, no manual registration list. - Compile-time group-name validation: Group names are compared at compile time whenever they are compile-time constants:
EPMG001— twoIEndpointGroupimplementations declare the sameGroupName.EPMG002— anIEndpointreferences aGroupNameno group declares.EPMG003— a generic endpoint/group type (the generated code cannot supply a type argument).EPMG004— a private or file-local endpoint/group type that the generated code cannot reference.EPMG005— static interface members implemented explicitly (they cannot be invoked by the generated code). Names computed at runtime are still resolved correctly at startup; mismatches among those fail with a descriptiveInvalidOperationExceptionnaming the endpoint type and the missing group key.
📝 Improvements
- Nested and internal endpoint types are fully supported; types that merely inherit the static contract from a base class are not registered twice.
- Updated
README.mdwith the newIEndpointGroup/IEndpointusage, compile-time validation behavior, and the simplifiedapp.MapEndpoints()Program.csflow.
Version 10.0.6
This release reorganizes extension methods into feature-specific classes and adds dynamic required header configuration.
⚠️ Breaking Changes
-
Extension methods reorganized into feature-specific classes: The generic classes
ApplicationBuilderExtensions,ServiceCollectionExtensions, andEndpointBuilderExtensionshave been replaced byHttpLoggingExtensions,ValidationExtensions, and a cleanedEndpointExtensions. All classes remain in the same namespace (RA.Utilities.Api.Extensions). Migration: No code changes are required for consuming projects — these are extension methods resolved by target type. If your code directly references the old class names (e.g., in unit tests or documentation), update those references. See the Migration Guide for details. -
Response Models Consolidated: All response model types from the now-deprecated
RA.Utilities.Api.Resultspackage have been merged into this package under theRA.Utilities.Api.Resultsnamespace. TheRA.Utilities.Api.ResultsNuGet package is no longer a dependency — update your package references and remove any direct dependency onRA.Utilities.Api.Results.
✨ New Features
-
New Exception Mappings:
ErrorResultMapperandErrorResultResponsenow handleTooManyRequestsException(429),ServiceUnavailableException(503), andGatewayTimeoutException(504) with their dedicated response types. -
Extension Methods Added:
AddRaExceptionHandling()andUseRaExceptionHandling()are now available as convenience extension methods onIServiceCollectionandIApplicationBuilder, matching the documented API.
✨ New Features
DefaultHeadersOptions.RequiredHeaders: The default headers middleware now supports dynamic configuration of required HTTP headers via aRequiredHeaderscollection. Each entry uses the newRequiredHeaderDefinitionmodel withName,AutoGenerate,EchoInResponse, andErrorMessageproperties.RequiredHeaderDefinitionmodel: New POCO class inRA.Utilities.Api.Optionsfor defining per-header enforcement behavior.
📝 Improvements
-
DefaultHeadersMiddlewareupdated: Now iterates overDefaultHeadersOptions.RequiredHeadersinstead of hardcodingx-request-id. Multiple missing headers are collected and returned in a single400 Bad Requestresponse. Default configuration preserves backward compatibility. -
HttpLoggingExtensionsclass:AddHttpLoggingMiddlewareandUseHttpLoggingMiddlewareare now paired in a single feature-focused class. -
EndpointExtensionscleaned: TheValidate<TModel>()method was extracted toValidationExtensions, keepingEndpointExtensionsfocused on endpoint discovery and mapping. -
Improved Logging:
GlobalExceptionHandlernow logs client errors (4xx) atWarninglevel and server errors (5xx) atErrorlevel, reducing log noise from expected client behavior. -
Consistency & Polish:
- Renamed static helper class
SuccessResponse→SuccessResultto resolve the naming collision withSuccessResponse<T>. - Removed unnecessary
where TResult : new()constraints onSuccessResulthelper methods. MapEndpointsnow returnsWebApplicationinstead ofIApplicationBuilderfor better fluent chaining.- Error dispatcher now uses
BaseResponseCodeconstants instead of hardcodedStatusCodesliterals. - Removed stale TODO comments and
<remarks>blocks fromEndpointExtensions.
- Renamed static helper class
-
README updated: Added documentation for
Validate<TModel>(),HttpLoggingMiddleware, andDefaultHeadersMiddlewarefeatures. -
Refined Documentation: Updated
README.mdto reflect all API changes, including corrected method signatures, new response type mappings, and the consolidation of response models.
Version 10.0.5
✨ Improvements & Fixes
- Dynamic Error Mapping: Updated
ErrorResultResponseto utilize theResponseCodedirectly fromRaBaseException. This allows domain-level exceptions to dictate the HTTP status code returned by the API. - Observability: Enhanced the global exception fallback to log unhandled exception messages and stack traces to the error console, aiding in production debugging.
- Clarity: Added internal documentation to the central error dispatcher to explain the pattern-matching logic.
Version 10.0.2
Add CreatedAtRoute methods to SuccessResponse for enhanced API response handling.
Version 10.0.1
✨ New Features: FluentValidation Integration for Minimal APIs
This release introduces a comprehensive integration with FluentValidation for ASP.NET Core Minimal APIs. You can now effortlessly validate incoming requests and automatically reflect those validation rules in your OpenAPI (Swagger) documentation. This creates a single source of truth for your validation logic, improving maintainability and providing a better experience for your API consumers.
1. Automatic Request Validation
A new endpoint filter has been introduced that automatically validates API request models. By simply adding .Validate<TModel>() to your endpoint definition, you can ensure that all incoming data is valid before your handler logic is executed. If validation fails, a standardized 400 Bad Request response is returned with detailed error information.
How to use it:
Chain the .Validate<TModel>() extension method to your endpoint registration.
// In your endpoint definition
app.MapPost("/users", (CreateUserRequest user) => {
// Handler logic here...
return SuccessResponse.Created(user);
})
.Validate<CreateUserRequest>(); // This enables automatic validation
This leverages the ValidationEndpointFilter<TModel>, which resolves your IValidator<TModel> implementations from the dependency injection container and executes them.
Version 10.0.0
Changed project version from a release candidate to final version 10.0.0 for production readiness.
Revised XML documentation comments to improve clarity and detail.
Improved the documentation in IEndpoint to clarify its purpose in grouping related API endpoints.
Adjusted parameter and return type descriptions in EndpointExtensions for better understanding of default assembly behavior.
Enhanced comments in SuccessResponse to explicitly state response wrapping behavior.
Version 10.0.0-rc.2
This release modernizes the RA.Utilities.Api package, introducing a suite of tools to build robust, consistent, and maintainable ASP.NET Core APIs. Key features include a .NET 8 global exception handler, helpers for standardized success responses, and a clean pattern for endpoint registration.
✨ New Features & Improvements
-
Global Exception Handling (
AddRaExceptionHandling):- Introduced a .NET 8
IExceptionHandlerimplementation that automatically catches exceptions and transforms them into standardized JSON error responses. - Catches semantic exceptions from
RA.Utilities.Core.Exceptions(e.g.,NotFoundException,ConflictException) and maps them to the correct HTTP status codes (404, 409, etc.). - Handles any unhandled exceptions by returning a generic 500 Internal Server Error to prevent leaking sensitive information.
- Introduced a .NET 8
-
Endpoint Registration Helpers (
AddEndpoints&MapEndpoints):- Provides a clean pattern for organizing API endpoints into separate files using the
IEndpointinterface. - Keeps
Program.csclean and maintainable by automatically discovering and registering all endpoint implementations in your project.
- Provides a clean pattern for organizing API endpoints into separate files using the
-
Standardized Success Response Helpers (
SuccessResponse):- Added a new static
SuccessResponseclass with helper methods (Ok,Created,NoContent, etc.). - These helpers simplify the creation of successful API responses and automatically wrap the payload in the standard
SuccessResponse<T>model, ensuring consistency with error responses.
- Added a new static
-
Seamless
Result<T>Integration:- The
SuccessResponsehelpers and the exception handling middleware work together to provide a clean way to handle theResult<T>type fromRA.Utilities.Core. - Use the
Matchmethod on aResultto map success outcomes toSuccessResponse.Ok()and failure outcomes directly to an exception that the middleware will handle.
- The
-
Comprehensive Documentation:
- The
README.mdhas been completely rewritten to provide clear, step-by-step instructions and usage examples for all major features.
- The
🚀 Getting Started
Register the services in your Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRaExceptionHandling();
builder.Services.AddEndpoints();
var app = builder.Build();
app.UseRaExceptionHandling();
app.MapEndpoints();