Skip to main content

Migration Guides

v10.2.3 → v10.3.0​

Additive changes:​

  • PaymentRequiredException maps to the new PaymentRequiredResponse (HTTP 402)
  • ErrorResultMapper.ToResponse(PaymentRequiredException) overload added
  • GlobalExceptionHandler logs PaymentRequiredException and TooManyRequestsException at Warning

No public signatures were removed or changed, so existing call sites compile without modification. The behavior change is in the exception dispatcher: before this release a PaymentRequiredException fell through to the RaBaseException arm and produced an HTTP 500 ErrorResponse; it now produces an HTTP 402 envelope.

Dependency changes​

v10.3.0 depends on RA.Utilities.Api.Response 10.2.0 (new PaymentRequiredResponse), RA.Utilities.Core.Exceptions 10.2.0 (new PaymentRequiredException), and RA.Utilities.Core.Constants 10.1.1 (BaseResponseCode.PaymentRequired, BaseResponseMessages.PaymentRequired, ResponseType.PaymentRequired).

What changed​

Aspectv10.2.3v10.3.0
PaymentRequiredException mappingHTTP 500 ErrorResponse (generic RaBaseException arm)HTTP 402 PaymentRequiredResponse
ErrorResultMapper—New ToResponse(PaymentRequiredException) overload
402/429 log levelErrorWarning
Success/error envelope—unchanged

Migration Steps​

1. No code changes required​

ErrorResultResponse.Result handles the new exception type internally, and the new mapper overload is additive. GlobalExceptionHandler picks up the mapping automatically.

2. Update clients that treated 402 as a server error​

If a client, retry policy, or alert currently classifies every 5xx as a server failure, review the paths that throw PaymentRequiredException: they now return 402 with responseType 18. Clients should treat 402 as a client/business outcome (paywall, exhausted quota) rather than an outage.

3. Align package versions​

Reference RA.Utilities.Api 10.3.0 so the transitive RA.Utilities.Api.Response 10.2.0 and RA.Utilities.Core.Exceptions 10.2.0 dependencies are resolved together.


v10.2.1 → v10.2.2​

Breaking Changes:​

  • MiddlewareExtensions split into ApplicationBuilderExtensions (Use* methods) and ServiceCollectionExtensions (Add* methods)

The single MiddlewareExtensions class is split into two classes that mirror the classic ASP.NET Core naming conventions: Add methods (service registration) live in ServiceCollectionExtensions, Use methods (pipeline registration) live in ApplicationBuilderExtensions. Both remain in the RA.Utilities.Api.Extensions namespace.

The extension methods themselves are unchanged — same names, same signatures. Because extension methods resolve by their target type (IServiceCollection / IApplicationBuilder), no call-site changes are required. Only code that references the class name directly (typeof(MiddlewareExtensions), static calls, unit-test naming) needs updating.

Additionally, the extension methods are refactored to C# 14 extension members (extension blocks), grouping each receiver's members in a single place. The public API surface is unchanged.

Dependency change: response models moved namespace​

v10.2.2 references RA.Utilities.Api.Response 10.1.0, which moved its models from RA.Utilities.Api.Results to RA.Utilities.Api.Response. The RA.Utilities.Api public API is unchanged; update using directives only if your own code imports the response models directly:

// Before
using RA.Utilities.Api.Results;

// After
using RA.Utilities.Api.Response;

What changed​

Aspectv10.2.1v10.2.2
Use* methodsMiddlewareExtensionsApplicationBuilderExtensions
Add* methodsMiddlewareExtensionsServiceCollectionExtensions
Method names / signatures—unchanged
Implementation styleclassic extension methodsC# 14 extension blocks

Migration Steps​

1. No code changes required for consuming projects​

These are extension methods — they are resolved by the compiler based on the target type (IServiceCollection, IApplicationBuilder), not the static class name. The using directive (using RA.Utilities.Api.Extensions;) is unchanged:

// ✅ This code is unchanged in v10.2.2
using RA.Utilities.Api.Extensions;

builder.Services.AddRaExceptionHandling(); // Resolved on IServiceCollection
builder.Services.AddDefaultHeadersMiddleware(); // Resolved on IServiceCollection
builder.Services.AddLoggingMiddleware(); // Resolved on IServiceCollection

var app = builder.Build();

app.UseRaExceptionHandling(); // Resolved on IApplicationBuilder
app.UseDefaultHeadersMiddleware(); // Resolved on IApplicationBuilder
app.UseLoggingMiddleware(); // Resolved on IApplicationBuilder
app.MapEndpoints();

2. Update direct class name references (if any)​

// ❌ v10.2.1
typeof(MiddlewareExtensions)

// ✅ v10.2.2
typeof(ApplicationBuilderExtensions) // Use* methods
typeof(ServiceCollectionExtensions) // Add* methods

v10.2.0 → v10.2.1​

Behavior Changes:​

  • LoggingMiddleware response log is written at LogLevel.Warning (previously undocumented)
  • LoggingMiddleware writes a dedicated slow-call warning entry when WarningThresholdMilliseconds is exceeded
  • HttpRequestLogTemplate / HttpResponseLogTemplate no longer carry RequestId / TraceIdentifier properties (via RA.Utilities.Logging.Shared v10.0.2)
  • RequestContextLoggingMiddleware renamed to ContextLoggingMiddleware (together with its Use extension method)

The LoggingMiddleware logging behavior is now explicit:

  • The request log (HTTP Request: {@RequestLog}) is written at LogLevel.Information.
  • The response log (HTTP Response: {@ResponseLog}) is written at LogLevel.Warning — and both logs are skipped entirely when Information logging is not enabled.
  • When the total elapsed time exceeds WarningThresholdMilliseconds, an additional Warning entry is written alongside the response log: HTTP call to {Method} {Url} took too long ({ElapsedMilliseconds} ms).

The RequestId and TraceIdentifier correlation properties were removed from the shared log templates. Correlation is now provided exclusively by the logging scope: every request processed by LoggingMiddleware runs inside a scope containing the x-request-id value (LoggingConstants.XRequestId), which sinks like the Serilog RequestIdEnricher (RA.Utilities.Logging.Core) pick up.

The request-context middleware type was renamed to better reflect its single responsibility: enriching the log scope with the request's X-Request-Id correlation ID. The Add extension method keeps its name; the Use method was renamed along with the type (UseRequestContextLoggingMiddleware() → UseContextLoggingMiddleware()).

What changed​

Aspectv10.2.0v10.2.1
Response log levelWarning (undocumented)Warning (documented)
Slow-call signalnoneAdditional Warning entry when WarningThresholdMilliseconds exceeded
Template correlation propertiesRequestId, TraceIdentifiernone — via log scope
Middleware typeRequestContextLoggingMiddlewareContextLoggingMiddleware
Registration methodsAddRequestContextLoggingMiddleware() / UseRequestContextLoggingMiddleware()AddRequestContextLoggingMiddleware() (unchanged) / UseContextLoggingMiddleware() (renamed)
BehaviorX-Request-Id log scopeunchanged

Migration Steps​

No code changes are required unless you:

  1. Queried RequestId / TraceIdentifier on the log templates — the properties no longer exist. Read the correlation ID from the log scope instead (e.g. LoggingConstants.XRequestId, surfaced by the Serilog RequestIdEnricher from RA.Utilities.Logging.Core).

  2. Filtered on Information level to see response logs — response logs are written at Warning; adjust level filters or alert rules accordingly.

  3. Referenced RequestContextLoggingMiddleware directly

tip

No code changes are required for ordinary call sites — only direct references to the middleware type or the old Use method need updating:

// ❌ v10.2.0
app.UseMiddleware<RequestContextLoggingMiddleware>();
services.AddTransient<RequestContextLoggingMiddleware>();
app.UseRequestContextLoggingMiddleware();

// ✅ v10.2.1
app.UseMiddleware<ContextLoggingMiddleware>();
services.AddTransient<ContextLoggingMiddleware>();
app.UseContextLoggingMiddleware(); // renamed from UseRequestContextLoggingMiddleware()

3.1 Unit tests or DI assertions naming the type — update typeof(RequestContextLoggingMiddleware) to typeof(ContextLoggingMiddleware).


v10.0.6 → v10.2.0​

Breaking Changes:​

  • IEndpoint redesigned into a static-abstract contract
  • EndpointExtensions (reflection-based AddEndpoints/MapEndpoints) removed

The instance-based IEndpoint interface (void MapEndpoint(IEndpointRouteBuilder app)) has been replaced by a static-abstract contract (static abstract string GroupName { get; } and static abstract void MapEndpoint(RouteGroupBuilder group)). Endpoint registration no longer uses reflection or DI scanning: a source generator shipped inside the package emits the app.MapEndpoints() implementation at compile time.

Why this change?​

  • The old pattern required reflection-based assembly scanning and DI registration at startup.
  • The new pipeline validates group names at compile time (EPMG001/EPMG002 diagnostics) instead of failing at runtime.
  • Endpoint types no longer need to be instantiable — they are referenced statically by the generated code.

What changed​

Aspectv10.0.6v10.2.0
Endpoint contractIEndpoint with void MapEndpoint(IEndpointRouteBuilder)IEndpoint with static abstract string GroupName + static abstract void MapEndpoint(RouteGroupBuilder)
Group definition—IEndpointGroup (new)
Registrationbuilder.Services.AddEndpoints(assembly) + app.MapEndpoints()app.MapEndpoints() only
DiscoveryReflection at startupSource generator at compile time

Migration Steps​

1. Convert each IEndpoint class​

// ❌ v10.0.6
public class ProductEndpoints : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapGet("/products", () => Results.Ok("All products"));
}
}

// ✅ v10.2.0
internal sealed class GetProductsEndpoint : IEndpoint
{
public static string GroupName => "Products";

public static void MapEndpoint(RouteGroupBuilder group)
{
group.MapGet("/", () => Results.Ok("All products"));
}
}

2. Add an IEndpointGroup per feature​

// Features/Products/ProductsGroup.cs
using RA.Utilities.Api.Abstractions;

internal sealed class ProductsGroup : IEndpointGroup
{
public static string GroupName => "Products";

public static RouteGroupBuilder MapGroup(IEndpointRouteBuilder app) =>
app.MapGroup("api/products").WithTags("Products");
}

3. Remove AddEndpoints from Program.cs​

// ❌ v10.0.6
builder.Services.AddEndpoints(typeof(Program).Assembly);

var app = builder.Build();
app.MapEndpoints();

// ✅ v10.2.0
var app = builder.Build();
app.MapEndpoints();

v10.0.5 → v10.0.6​

Breaking Change:​

  • Extension methods reorganized into feature-specific classes
  • SuccessResponse renamed to SuccessResult

The static helper class SuccessResponse was renamed to SuccessResult to resolve a naming collision with the generic response model SuccessResponse<T>. The generic extension classes ApplicationBuilderExtensions, ServiceCollectionExtensions, and EndpointBuilderExtensions have been replaced with feature-specific alternatives. All classes remain in the same namespace (RA.Utilities.Api.Extensions).

Why this change?​

  • Having both SuccessResponse (static helper class) and SuccessResponse<T> (generic response model) in the same namespace caused ambiguity and IDE confusion.
  • SuccessResult better describes what the class does — it creates IResult objects.
  • The old naming (ApplicationBuilderExtensions, ServiceCollectionExtensions) was too generic — each class held only one method and provided no hint about what feature it related to. The new organization follows the pattern established by ExceptionHandlingExtensions, where each file is a self-contained feature with its Add/Use pair.

What changed​

Aspectv10.0.5v10.0.6
AddLoggingMiddleware locationServiceCollectionExtensionsHttpLoggingExtensions
UseLoggingMiddleware locationApplicationBuilderExtensionsHttpLoggingExtensions
Validate<TModel> locationEndpointBuilderExtensionsValidationExtensions
AddEndpoints locationEndpointExtensionsEndpointExtensions (unchanged)
MapEndpoints locationEndpointExtensionsEndpointExtensions (unchanged)
AddRaExceptionHandling locationRaExceptionHandlingExtensionsExceptionHandlingExtensions
UseRaExceptionHandling locationRaExceptionHandlingExtensionsExceptionHandlingExtensions
AddDefaultHeadersMiddleware location—DefaultHeadersMiddlewareExtensions (new)
UseDefaultHeadersMiddleware location—DefaultHeadersMiddlewareExtensions (new)
AddRequestContextLoggingMiddleware location—RequestContextLoggingMiddlewareExtensions (new)
UseRequestContextLoggingMiddleware location—RequestContextLoggingMiddlewareExtensions (new)

Migration Steps​

1. No code changes required for consuming projects​

These are extension methods — they are resolved by the compiler based on the target type (IServiceCollection, IApplicationBuilder, RouteHandlerBuilder, WebApplication), not the static class name. The using directive (using RA.Utilities.Api.Extensions;) is unchanged. Your existing Program.cs code continues to compile without modification:

// ✅ This code is unchanged in v10.0.6
using RA.Utilities.Api.Extensions;

builder.Services.AddLoggingMiddleware(); // Resolved on IServiceCollection
builder.Services.AddEndpoints(typeof(Program).Assembly); // Resolved on IServiceCollection
builder.Services.AddRaExceptionHandling(); // Resolved on IServiceCollection

var app = builder.Build();

app.UseLoggingMiddleware(); // Resolved on IApplicationBuilder
app.UseRaExceptionHandling(); // Resolved on IApplicationBuilder
app.MapEndpoints(); // Resolved on WebApplication

2. Rename all references​

// ❌ v10.0.5
using RA.Utilities.Api.Mapper;
return SuccessResponse.Ok(product);

// ✅ v10.0.6
using RA.Utilities.Api.Mapper;
return SuccessResult.Ok(product);

3. Response Models Extracted to a Standalone Package​

The response model types are published in the standalone RA.Utilities.Api.Response package again. RA.Utilities.Api depends on it, so existing projects receive the types transitively — no package changes are required. To reference the models directly:

dotnet add package RA.Utilities.Api.Response

With RA.Utilities.Api.Response v10.1.0+, the types live in the RA.Utilities.Api.Response namespace. Replace using RA.Utilities.Api.Results; with using RA.Utilities.Api.Response;. See the Api.Response migration guide for the full before/after steps.

4. Update direct class name references (if any)​

If your code directly references the old class names (unlikely for extension methods, but possible in unit tests or custom reflection code), update them:

// ❌ Old class names (removed)
typeof(ServiceCollectionExtensions)
typeof(ApplicationBuilderExtensions)
typeof(EndpointBuilderExtensions)

// ✅ New class names
typeof(HttpLoggingExtensions)
typeof(ValidationExtensions)
// EndpointExtensions is unchanged

5. Test files​

If you have test files named after the old classes, rename them for clarity:

Old test classNew test class
EndpointBuilderExtensionsTestsValidationExtensionsTests

Full Changelog​

See the package release notes for a complete version history.