Skip to main content

RA.Utilities.Api

· 13 min read
Redon Alla
.NET, React, Angular Developer

Version 10.4.0​

Date Badge NuGet version

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​

  • ApiVersionSet threading: app.MapEndpoints(apiVersionSet) forwards the version set to every MapGroup(IEndpointRouteBuilder, ApiVersionSet?) and MapEndpoint(RouteGroupBuilder, ApiVersionSet?) implementation, matching the standard app.MapGroup(...).WithApiVersionSet(apiVersionSet) pattern. The package now references Asp.Versioning.Http (10.x), which flows to consumers transitively; the parameter is optional, so unversioned APIs just call app.MapEndpoints().

⚠️ Breaking Changes​

  • IEndpointGroup/IEndpoint signatures: MapGroup and MapEndpoint implementations must declare the new optional ApiVersionSet? apiVersionSet = null parameter (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​

Date Badge NuGet version

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 a Results.Json result with status code 402, and the new ErrorResultMapper.ToResponse(PaymentRequiredException) overload builds a PaymentRequiredResponse from the exception's code and message (result stays null). Previously the exception fell through to the RaBaseException arm and produced an HTTP 500 ErrorResponse. Requires RA.Utilities.Api.Response 10.2.0, RA.Utilities.Core.Exceptions 10.2.0, and RA.Utilities.Core.Constants 10.1.1.

📝 Improvements​

  • Client-error logging: GlobalExceptionHandler treats PaymentRequiredException and TooManyRequestsException as client errors, so both are logged at Warning instead of Error. ServiceUnavailableException, GatewayTimeoutException, and other RaBaseException types remain at Error.

Version 10.2.3​

Date Badge NuGet version

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) and DefaultHeadersMiddleware now import the response models from RA.Utilities.Api.Response instead of the transitional RA.Utilities.Api.Results namespace, and the verbose Microsoft.AspNetCore.Http.Results.* qualifications are simplified to Results.*. Call sites are unaffected.
  • FluentValidation 12.1.1 → 12.2.0.

Version 10.2.2​

Date Badge NuGet version

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​

  • MiddlewareExtensions split into ApplicationBuilderExtensions and ServiceCollectionExtensions: the Add* methods live in ServiceCollectionExtensions (extension members on IServiceCollection), the Use* methods in ApplicationBuilderExtensions (extension members on IApplicationBuilder). Call sites need no changes — extension methods resolve by target type — but code that references the MiddlewareExtensions class 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, and ValidationExtensions now declare their methods inside extension(...) blocks on IApplicationBuilder, IServiceCollection, and RouteHandlerBuilder respectively. The generated extension methods have identical names and signatures, so the refactor is source-compatible for all callers.

  • ValidationExtensions refactored: Validate<TModel>() is now a member of an extension(RouteHandlerBuilder builder) block. The calling syntax is unchanged: app.MapPost(...).Validate<CreateRequest>().

  • Response model dependency updated: the package now references RA.Utilities.Api.Response 10.1.0, whose models moved from the RA.Utilities.Api.Results namespace to RA.Utilities.Api.Response. The mapper and header middleware use the new namespace. Consumer code only needs a using update 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​

Date Badge NuGet version

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 (via RA.Utilities.Logging.Shared 10.0.2): structured request/response logs produced by LoggingMiddleware no 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.

  • RequestContextLoggingMiddleware renamed to ContextLoggingMiddleware: code that references the middleware type directly — custom UseMiddleware<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 method AddRequestContextLoggingMiddleware() 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 at LogLevel.Warning; the request log remains at LogLevel.Information, and both are skipped when Information is 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 additional Warning entry 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-Id correlation ID for every request.

Version 10.1.0​

Date Badge NuGet version

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​

  • IEndpoint redesigned: The instance-based IEndpoint interface (void MapEndpoint(IEndpointRouteBuilder)) has been replaced by a static-abstract contract: static abstract string GroupName { get; } and static abstract void MapEndpoint(RouteGroupBuilder group). Endpoint classes are now referenced statically by the generated registration code and no longer need to be instantiable.
  • EndpointExtensions removed: The reflection-based AddEndpoints/MapEndpoints extension methods have been removed. The app.MapEndpoints() call now maps every IEndpointGroup and IEndpoint implementation discovered at compile time by the source generator.
  • Middleware extension classes consolidated into MiddlewareExtensions: DefaultHeadersMiddlewareExtensions, ExceptionHandlingExtensions, LoggingMiddlewareExtensions, and RequestContextLoggingMiddlewareExtensions have been merged into a single MiddlewareExtensions class (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​

  • IEndpointGroup interface: 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 for IEndpointGroup and IEndpoint implementations and emits the MapEndpoints() 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 — two IEndpointGroup implementations declare the same GroupName.
    • EPMG002 — an IEndpoint references a GroupName no 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 descriptive InvalidOperationException naming 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.md with the new IEndpointGroup/IEndpoint usage, compile-time validation behavior, and the simplified app.MapEndpoints() Program.cs flow.

Version 10.0.6​

Date Badge NuGet version

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, and EndpointBuilderExtensions have been replaced by HttpLoggingExtensions, ValidationExtensions, and a cleaned EndpointExtensions. 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.Results package have been merged into this package under the RA.Utilities.Api.Results namespace. The RA.Utilities.Api.Results NuGet package is no longer a dependency — update your package references and remove any direct dependency on RA.Utilities.Api.Results.

✨ New Features​

  • New Exception Mappings: ErrorResultMapper and ErrorResultResponse now handle TooManyRequestsException (429), ServiceUnavailableException (503), and GatewayTimeoutException (504) with their dedicated response types.

  • Extension Methods Added: AddRaExceptionHandling() and UseRaExceptionHandling() are now available as convenience extension methods on IServiceCollection and IApplicationBuilder, matching the documented API.

✨ New Features​

  • DefaultHeadersOptions.RequiredHeaders: The default headers middleware now supports dynamic configuration of required HTTP headers via a RequiredHeaders collection. Each entry uses the new RequiredHeaderDefinition model with Name, AutoGenerate, EchoInResponse, and ErrorMessage properties.
  • RequiredHeaderDefinition model: New POCO class in RA.Utilities.Api.Options for defining per-header enforcement behavior.

📝 Improvements​

  • DefaultHeadersMiddleware updated: Now iterates over DefaultHeadersOptions.RequiredHeaders instead of hardcoding x-request-id. Multiple missing headers are collected and returned in a single 400 Bad Request response. Default configuration preserves backward compatibility.

  • HttpLoggingExtensions class: AddHttpLoggingMiddleware and UseHttpLoggingMiddleware are now paired in a single feature-focused class.

  • EndpointExtensions cleaned: The Validate<TModel>() method was extracted to ValidationExtensions, keeping EndpointExtensions focused on endpoint discovery and mapping.

  • Improved Logging: GlobalExceptionHandler now logs client errors (4xx) at Warning level and server errors (5xx) at Error level, reducing log noise from expected client behavior.

  • Consistency & Polish:

    • Renamed static helper class SuccessResponse → SuccessResult to resolve the naming collision with SuccessResponse<T>.
    • Removed unnecessary where TResult : new() constraints on SuccessResult helper methods.
    • MapEndpoints now returns WebApplication instead of IApplicationBuilder for better fluent chaining.
    • Error dispatcher now uses BaseResponseCode constants instead of hardcoded StatusCodes literals.
    • Removed stale TODO comments and <remarks> blocks from EndpointExtensions.
  • README updated: Added documentation for Validate<TModel>(), HttpLoggingMiddleware, and DefaultHeadersMiddleware features.

  • Refined Documentation: Updated README.md to reflect all API changes, including corrected method signatures, new response type mappings, and the consolidation of response models.

Version 10.0.5​

Date Badge NuGet version

✨ Improvements & Fixes​

  • Dynamic Error Mapping: Updated ErrorResultResponse to utilize the ResponseCode directly from RaBaseException. 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​

Date Badge NuGet version

Add CreatedAtRoute methods to SuccessResponse for enhanced API response handling.

Version 10.0.1​

Date Badge NuGet version

✨ 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​

Date Badge NuGet version

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​

Date Badge NuGet version

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 IExceptionHandler implementation 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.
  • Endpoint Registration Helpers (AddEndpoints & MapEndpoints):

    • Provides a clean pattern for organizing API endpoints into separate files using the IEndpoint interface.
    • Keeps Program.cs clean and maintainable by automatically discovering and registering all endpoint implementations in your project.
  • Standardized Success Response Helpers (SuccessResponse):

    • Added a new static SuccessResponse class 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.
  • Seamless Result<T> Integration:

    • The SuccessResponse helpers and the exception handling middleware work together to provide a clean way to handle the Result<T> type from RA.Utilities.Core.
    • Use the Match method on a Result to map success outcomes to SuccessResponse.Ok() and failure outcomes directly to an exception that the middleware will handle.
  • Comprehensive Documentation:

    • The README.md has been completely rewritten to provide clear, step-by-step instructions and usage examples for all major features.

🚀 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();