Table of Contents

Class HttpResultExtensionsAsync

Namespace
Trellis.Asp
Assembly
Trellis.Asp.dll

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

resultTask Task<Result<TValue>>

The task containing the result object to convert.

routeName string

The name of the route to use for generating the Location header URL.

routeValues Func<TValue, RouteValueDictionary>

A function that extracts route values from the result value for URL generation. Return a RouteValueDictionary to remain AOT-compatible.

options TrellisAspOptions

Optional 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

TValue

The type of the value contained in the result.

Remarks

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

resultTask ValueTask<Result<TValue>>

The ValueTask containing the result object to convert.

routeName string

The name of the route to use for generating the Location header URL.

routeValues Func<TValue, RouteValueDictionary>

A function that extracts route values from the result value for URL generation.

options TrellisAspOptions

Optional 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

TValue

The 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

resultTask Task<Result<TValue>>

The task containing the result object to convert.

routeName string

The name of the route to use for generating the Location header URL.

routeValues Func<TValue, RouteValueDictionary>

A function that extracts route values from the result value for URL generation.

map Func<TValue, TOut>

A function that transforms the input value to the output type for the response body.

options TrellisAspOptions

Optional 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

TValue

The type of the value contained in the input result.

TOut

The type of the value in the response body.

Remarks

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

resultTask ValueTask<Result<TValue>>

The ValueTask containing the result object to convert.

routeName string

The name of the route to use for generating the Location header URL.

routeValues Func<TValue, RouteValueDictionary>

A function that extracts route values from the result value for URL generation.

map Func<TValue, TOut>

A function that transforms the input value to the output type for the response body.

options TrellisAspOptions

Optional 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

TValue

The type of the value contained in the input result.

TOut

The 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

resultTask Task<Result<TIn>>
httpContext HttpContext
uriSelector Func<TIn, string>
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

Task<IResult>

Type Parameters

TIn
TOut

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

resultTask ValueTask<Result<TIn>>
httpContext HttpContext
uriSelector Func<TIn, string>
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

ValueTask<IResult>

Type Parameters

TIn
TOut

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

resultTask Task<Result<TValue>>
from long
to long
totalLength long
options TrellisAspOptions

Returns

Task<IResult>

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

resultTask Task<Result<TValue>>

The task containing the result object to convert.

options TrellisAspOptions

Optional 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

TValue

The 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

resultTask ValueTask<Result<TValue>>
from long
to long
totalLength long
options TrellisAspOptions

Returns

ValueTask<IResult>

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

resultTask ValueTask<Result<TValue>>

The ValueTask containing the result object to convert.

options TrellisAspOptions

Optional 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

TValue

The 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

resultTask Task<Result<TIn>>
httpContext HttpContext
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

Task<IResult>

Type Parameters

TIn
TOut

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

resultTask Task<Result<TIn>>
funcRange Func<TIn, ContentRangeHeaderValue>
funcValue Func<TIn, TOut>
options TrellisAspOptions

Returns

Task<IResult>

Type Parameters

TIn
TOut

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

resultTask ValueTask<Result<TIn>>
httpContext HttpContext
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

ValueTask<IResult>

Type Parameters

TIn
TOut

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

resultTask ValueTask<Result<TIn>>
funcRange Func<TIn, ContentRangeHeaderValue>
funcValue Func<TIn, TOut>
options TrellisAspOptions

Returns

ValueTask<IResult>

Type Parameters

TIn
TOut

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

resultTask Task<Result<TIn>>
httpContext HttpContext
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

Task<IResult>

Type Parameters

TIn
TOut

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

resultTask Task<Result<TIn>>
httpContext HttpContext
metadata RepresentationMetadata
map Func<TIn, TOut>
options TrellisAspOptions

Returns

Task<IResult>

Type Parameters

TIn
TOut

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

resultTask ValueTask<Result<TIn>>
httpContext HttpContext
metadataSelector Func<TIn, RepresentationMetadata>
map Func<TIn, TOut>
options TrellisAspOptions

Returns

ValueTask<IResult>

Type Parameters

TIn
TOut

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

resultTask ValueTask<Result<TIn>>
httpContext HttpContext
metadata RepresentationMetadata
map Func<TIn, TOut>
options TrellisAspOptions

Returns

ValueTask<IResult>

Type Parameters

TIn
TOut