Class HttpResultExtensionsAsync
Provides asynchronous extension methods to convert Task/ValueTask-wrapped Result types to ASP.NET Core Minimal API IResult responses. These methods enable clean async patterns in Minimal API endpoints while maintaining Railway Oriented Programming benefits.
public static class HttpResultExtensionsAsync
- Inheritance
-
HttpResultExtensionsAsync
- Inherited Members
Remarks
These extensions are async variants of HttpResultExtensions, designed for use with async service methods in Minimal APIs. They support both Task<TResult> and ValueTask<TResult> for maximum flexibility and performance.
Key benefits:
- Clean async Minimal API endpoint code without manual awaiting
- Automatic HTTP status code selection based on error type
- Support for both Task and ValueTask for performance optimization
- Consistent error handling across async operations
- Seamless integration with async Railway Oriented Programming chains
- Reduced boilerplate in endpoint definitions
Usage pattern in async Minimal APIs (with CancellationToken):
app.MapGet("/users/{id}", async (string id, IUserService userService, CancellationToken ct) =>
await UserId.TryCreate(id)
.BindAsync(userId => userService.GetUserAsync(userId, ct))
.MapAsync(user => new UserDto(user))
.ToHttpResultAsync()
);
Best Practice: Always accept a CancellationToken parameter in async endpoints and pass it through to all async service calls. ASP.NET Core automatically provides request cancellation through this token, enabling proper timeout handling and graceful shutdown.
Methods
ToCreatedAtRouteHttpResultAsync<TValue>(Task<Result<TValue>>, string, Func<TValue, RouteValueDictionary>, TrellisAspOptions?)
Converts a Task-wrapped Result<TValue> to an IResult that returns 201 Created with a Location header on success, or Problem Details on failure.
public static Task<IResult> ToCreatedAtRouteHttpResultAsync<TValue>(this Task<Result<TValue>> resultTask, string routeName, Func<TValue, RouteValueDictionary> routeValues, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TValue>>The task containing the result object to convert.
routeNamestringThe name of the route to use for generating the Location header URL.
routeValuesFunc<TValue, RouteValueDictionary>A function that extracts route values from the result value for URL generation. Return a RouteValueDictionary to remain AOT-compatible.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- Task<IResult>
A task that represents the asynchronous operation, containing:
- 201 Created with Location header and value if result is successful
- Appropriate error status code (400-599) based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Remarks
Async variant of ToCreatedAtRouteHttpResult<TValue>(Result<TValue>, string, Func<TValue, RouteValueDictionary>, TrellisAspOptions?).
ToCreatedAtRouteHttpResultAsync<TValue>(ValueTask<Result<TValue>>, string, Func<TValue, RouteValueDictionary>, TrellisAspOptions?)
Converts a ValueTask-wrapped Result<TValue> to an IResult that returns 201 Created with a Location header on success, or Problem Details on failure.
public static ValueTask<IResult> ToCreatedAtRouteHttpResultAsync<TValue>(this ValueTask<Result<TValue>> resultTask, string routeName, Func<TValue, RouteValueDictionary> routeValues, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TValue>>The ValueTask containing the result object to convert.
routeNamestringThe name of the route to use for generating the Location header URL.
routeValuesFunc<TValue, RouteValueDictionary>A function that extracts route values from the result value for URL generation.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- ValueTask<IResult>
A ValueTask that represents the asynchronous operation, containing:
- 201 Created with Location header and value if result is successful
- Appropriate error status code (400-599) based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Remarks
ValueTask variant optimized for scenarios with cached or frequently synchronous results.
ToCreatedAtRouteHttpResultAsync<TValue, TOut>(Task<Result<TValue>>, string, Func<TValue, RouteValueDictionary>, Func<TValue, TOut>, TrellisAspOptions?)
Converts a Task-wrapped Result<TValue> to an IResult that returns 201 Created with a Location header on success (with value transformation), or Problem Details on failure.
public static Task<IResult> ToCreatedAtRouteHttpResultAsync<TValue, TOut>(this Task<Result<TValue>> resultTask, string routeName, Func<TValue, RouteValueDictionary> routeValues, Func<TValue, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TValue>>The task containing the result object to convert.
routeNamestringThe name of the route to use for generating the Location header URL.
routeValuesFunc<TValue, RouteValueDictionary>A function that extracts route values from the result value for URL generation.
mapFunc<TValue, TOut>A function that transforms the input value to the output type for the response body.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- Task<IResult>
A task that represents the asynchronous operation, containing:
- 201 Created with Location header and mapped value if result is successful
- Appropriate error status code (400-599) based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the input result.
TOutThe type of the value in the response body.
Remarks
Async variant of ToCreatedAtRouteHttpResult<TValue, TOut>(Result<TValue>, string, Func<TValue, RouteValueDictionary>, Func<TValue, TOut>, TrellisAspOptions?).
ToCreatedAtRouteHttpResultAsync<TValue, TOut>(ValueTask<Result<TValue>>, string, Func<TValue, RouteValueDictionary>, Func<TValue, TOut>, TrellisAspOptions?)
Converts a ValueTask-wrapped Result<TValue> to an IResult that returns 201 Created with a Location header on success (with value transformation), or Problem Details on failure.
public static ValueTask<IResult> ToCreatedAtRouteHttpResultAsync<TValue, TOut>(this ValueTask<Result<TValue>> resultTask, string routeName, Func<TValue, RouteValueDictionary> routeValues, Func<TValue, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TValue>>The ValueTask containing the result object to convert.
routeNamestringThe name of the route to use for generating the Location header URL.
routeValuesFunc<TValue, RouteValueDictionary>A function that extracts route values from the result value for URL generation.
mapFunc<TValue, TOut>A function that transforms the input value to the output type for the response body.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- ValueTask<IResult>
A ValueTask that represents the asynchronous operation, containing:
- 201 Created with Location header and mapped value if result is successful
- Appropriate error status code (400-599) based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the input result.
TOutThe type of the value in the response body.
Remarks
ValueTask variant optimized for scenarios with cached or frequently synchronous results.
ToCreatedHttpResultAsync<TIn, TOut>(Task<Result<TIn>>, HttpContext, Func<TIn, string>, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async Task overload: converts result to 201 Created Minimal API IResult with metadata headers.
public static Task<IResult> ToCreatedHttpResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, string> uriSelector, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TIn>>httpContextHttpContexturiSelectorFunc<TIn, string>metadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToCreatedHttpResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, HttpContext, Func<TIn, string>, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async ValueTask overload: converts result to 201 Created Minimal API IResult with metadata headers.
public static ValueTask<IResult> ToCreatedHttpResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, string> uriSelector, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TIn>>httpContextHttpContexturiSelectorFunc<TIn, string>metadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToHttpResultAsync<TValue>(Task<Result<TValue>>, long, long, long, TrellisAspOptions?)
Async Task overload: converts result to 206 Partial Content or 200 OK with range parameters.
public static Task<IResult> ToHttpResultAsync<TValue>(this Task<Result<TValue>> resultTask, long from, long to, long totalLength, TrellisAspOptions? options = null)
Parameters
Returns
Type Parameters
TValue
ToHttpResultAsync<TValue>(Task<Result<TValue>>, TrellisAspOptions?)
Converts a Task-wrapped Result<TValue> to an IResult with appropriate HTTP status code.
public static Task<IResult> ToHttpResultAsync<TValue>(this Task<Result<TValue>> resultTask, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TValue>>The task containing the result object to convert.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- Task<IResult>
A task that represents the asynchronous operation, containing:
- 200 OK with value if result is successful (except for Unit)
- 204 No Content if result is successful and TValue is Unit
- Appropriate error status code (400-599) based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Examples
Async GET endpoint with database query and CancellationToken:
app.MapGet("/users/{id}", async (Guid id, IUserRepository repository, CancellationToken ct) =>
await UserId.TryCreate(id)
.BindAsync(userId => repository.GetByIdAsync(userId, ct))
.MapAsync(user => new UserDto(user))
.ToHttpResultAsync());
// Success: 200 OK with UserDto
// Not found: 404 Not Found with Problem Details
// Validation error: 400 Bad Request
Async POST endpoint with multiple operations and CancellationToken:
app.MapPost("/orders", async (
CreateOrderRequest request,
IOrderService orderService,
IEventBus eventBus,
CancellationToken ct) =>
await CustomerId.TryCreate(request.CustomerId)
.BindAsync(customerId => orderService.GetCustomerAsync(customerId, ct))
.BindAsync(customer => orderService.CreateOrderAsync(customer, request.Items, ct))
.TapAsync(order => eventBus.PublishAsync(new OrderCreatedEvent(order.Id), ct))
.MapAsync(order => new OrderDto(order))
.ToHttpResultAsync());
// Success: 200 OK with OrderDto
// Validation error: 400 Bad Request
// Customer not found: 404 Not Found
// Domain error: 422 Unprocessable Entity
Async DELETE endpoint returning Unit with CancellationToken:
app.MapDelete("/users/{id}", async (Guid id, IUserRepository repository, CancellationToken ct) =>
await UserId.TryCreate(id)
.BindAsync(userId => repository.DeleteAsync(userId, ct))
.ToHttpResultAsync());
// Success: 204 No Content (automatic for Unit)
// Not found: 404 Not Found
Complex async workflow with validation and side effects:
app.MapPost("/payments", async (
ProcessPaymentRequest request,
IPaymentService paymentService,
INotificationService notificationService,
CancellationToken ct) =>
await Amount.TryCreate(request.Amount)
.Combine(CardNumber.TryCreate(request.CardNumber))
.BindAsync((amount, card) =>
paymentService.ProcessPaymentAsync(amount, card, ct))
.TapAsync(payment =>
notificationService.SendReceiptAsync(payment, ct))
.MapAsync(payment => new PaymentDto(payment))
.ToHttpResultAsync());
// Returns appropriate status codes for validation errors,
// payment failures, or successful processing
Remarks
This is the primary async method for converting domain results to HTTP responses in Minimal APIs. It awaits the result task and delegates to ToHttpResult<TValue>(Result<TValue>, TrellisAspOptions?).
For performance-critical scenarios where the operation frequently completes synchronously, consider using the ValueTask overload instead.
CancellationToken Best Practice: The endpoint should accept a CancellationToken parameter (ASP.NET Core automatically provides request cancellation) and pass it to all async service calls in the chain.
ToHttpResultAsync<TValue>(ValueTask<Result<TValue>>, long, long, long, TrellisAspOptions?)
Async ValueTask overload: converts result to 206 Partial Content or 200 OK with range parameters.
public static ValueTask<IResult> ToHttpResultAsync<TValue>(this ValueTask<Result<TValue>> resultTask, long from, long to, long totalLength, TrellisAspOptions? options = null)
Parameters
Returns
Type Parameters
TValue
ToHttpResultAsync<TValue>(ValueTask<Result<TValue>>, TrellisAspOptions?)
Converts a ValueTask-wrapped Result<TValue> to an IResult with appropriate HTTP status code.
public static ValueTask<IResult> ToHttpResultAsync<TValue>(this ValueTask<Result<TValue>> resultTask, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TValue>>The ValueTask containing the result object to convert.
optionsTrellisAspOptionsOptional custom error-to-status-code mappings. When null, uses default mappings.
Returns
- ValueTask<IResult>
A ValueTask that represents the asynchronous operation, containing:
- 200 OK with value if result is successful (except for Unit)
- 204 No Content if result is successful and TValue is Unit
- Appropriate error status code based on error type if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Examples
Using with cached data that might complete synchronously:
app.MapGet("/users/{id}", async (Guid id, IUserCache cache, CancellationToken ct) =>
await UserId.TryCreate(id)
.BindAsync(userId => cache.GetUserAsync(userId, ct)) // Returns ValueTask
.MapAsync(user => new UserDto(user))
.ToHttpResultAsync());
// Optimized for frequent cache hits that complete synchronously
High-performance endpoint with ValueTask throughout:
app.MapGet("/metrics/{id}", async (string id, IMetricsService service, CancellationToken ct) =>
await MetricId.TryCreate(id)
.BindAsync(metricId => service.GetMetricAsync(metricId, ct)) // ValueTask
.MapAsync(metric => new MetricDto(metric))
.ToHttpResultAsync());
// Reduced allocations for high-throughput scenarios
Remarks
This overload is optimized for scenarios where the async operation frequently completes synchronously (e.g., cached results, in-memory operations, ValueTask-returning service methods). ValueTask can reduce allocations in these cases.
Use this when your service methods return ValueTask for performance optimization.
ToHttpResultAsync<TIn, TOut>(Task<Result<TIn>>, HttpContext, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async Task overload: converts result to Minimal API IResult with metadata headers and conditional request evaluation.
public static Task<IResult> ToHttpResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TIn>>httpContextHttpContextmetadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToHttpResultAsync<TIn, TOut>(Task<Result<TIn>>, Func<TIn, ContentRangeHeaderValue>, Func<TIn, TOut>, TrellisAspOptions?)
Async Task overload: converts result to 206 Partial Content or 200 OK with lambda-based Content-Range.
public static Task<IResult> ToHttpResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, Func<TIn, ContentRangeHeaderValue> funcRange, Func<TIn, TOut> funcValue, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TIn>>funcRangeFunc<TIn, ContentRangeHeaderValue>funcValueFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToHttpResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, HttpContext, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async ValueTask overload: converts result to Minimal API IResult with metadata headers and conditional request evaluation.
public static ValueTask<IResult> ToHttpResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TIn>>httpContextHttpContextmetadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToHttpResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, Func<TIn, ContentRangeHeaderValue>, Func<TIn, TOut>, TrellisAspOptions?)
Async ValueTask overload: converts result to 206 Partial Content or 200 OK with lambda-based Content-Range.
public static ValueTask<IResult> ToHttpResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, Func<TIn, ContentRangeHeaderValue> funcRange, Func<TIn, TOut> funcValue, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TIn>>funcRangeFunc<TIn, ContentRangeHeaderValue>funcValueFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToUpdatedHttpResultAsync<TIn, TOut>(Task<Result<TIn>>, HttpContext, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async Task overload: converts result to an updated Minimal API response with dynamic metadata and Prefer support.
public static Task<IResult> ToUpdatedHttpResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TIn>>httpContextHttpContextmetadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToUpdatedHttpResultAsync<TIn, TOut>(Task<Result<TIn>>, HttpContext, RepresentationMetadata?, Func<TIn, TOut>, TrellisAspOptions?)
Async Task overload: converts result to an updated Minimal API response with Prefer support.
public static Task<IResult> ToUpdatedHttpResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, HttpContext httpContext, RepresentationMetadata? metadata, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskTask<Result<TIn>>httpContextHttpContextmetadataRepresentationMetadatamapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToUpdatedHttpResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, HttpContext, Func<TIn, RepresentationMetadata>, Func<TIn, TOut>, TrellisAspOptions?)
Async ValueTask overload: converts result to an updated Minimal API response with dynamic metadata and Prefer support.
public static ValueTask<IResult> ToUpdatedHttpResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, HttpContext httpContext, Func<TIn, RepresentationMetadata> metadataSelector, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TIn>>httpContextHttpContextmetadataSelectorFunc<TIn, RepresentationMetadata>mapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut
ToUpdatedHttpResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, HttpContext, RepresentationMetadata?, Func<TIn, TOut>, TrellisAspOptions?)
Async ValueTask overload: converts result to an updated Minimal API response with Prefer support.
public static ValueTask<IResult> ToUpdatedHttpResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, HttpContext httpContext, RepresentationMetadata? metadata, Func<TIn, TOut> map, TrellisAspOptions? options = null)
Parameters
resultTaskValueTask<Result<TIn>>httpContextHttpContextmetadataRepresentationMetadatamapFunc<TIn, TOut>optionsTrellisAspOptions
Returns
Type Parameters
TInTOut