Class ActionResultExtensionsAsync
- Namespace
- FunctionalDdd
- Assembly
- FunctionalDdd.Asp.dll
Provides asynchronous extension methods to convert Task/ValueTask-wrapped Result types to ASP.NET Core ActionResult responses. These methods enable clean async/await patterns in controllers while maintaining Railway Oriented Programming benefits.
public static class ActionResultExtensionsAsync
- Inheritance
-
ActionResultExtensionsAsync
- Inherited Members
Remarks
These extensions are async variants of ActionResultExtensions, designed for use with async service methods. They support both Task<TResult> and ValueTask<TResult> for maximum flexibility and performance.
Key benefits:
- Clean async controller 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
Usage pattern in async controllers (with CancellationToken):
public class UsersController : ControllerBase
{
[HttpGet("{id}")]
public Task<ActionResult<UserDto>> GetUserAsync(string id, CancellationToken ct) =>
UserId.TryCreate(id)
.BindAsync(userId => _userService.GetUserAsync(userId, ct))
.MapAsync(user => new UserDto(user))
.ToActionResultAsync(this);
}
Best Practice: Always accept a CancellationToken parameter in async controller methods and pass it through to all async service calls. This enables proper request cancellation, graceful shutdown, and timeout handling.
Methods
ToActionResultAsync<TValue>(Task<Result<TValue>>, ControllerBase)
Converts a Task-wrapped Result<TValue> to an ActionResult<TValue> with appropriate HTTP status code.
public static Task<ActionResult<TValue>> ToActionResultAsync<TValue>(this Task<Result<TValue>> resultTask, ControllerBase controllerBase)
Parameters
resultTaskTask<Result<TValue>>The task containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
Returns
- Task<ActionResult<TValue>>
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:
[HttpGet("{id}")]
public Task<ActionResult<UserDto>> GetUserAsync(Guid id, CancellationToken ct) =>
UserId.TryCreate(id)
.BindAsync(userId => _repository.GetByIdAsync(userId, ct))
.MapAsync(user => new UserDto(user))
.ToActionResultAsync(this);
// Success: 200 OK with UserDto
// Not found: 404 Not Found with Problem Details
Async POST endpoint with multiple operations and CancellationToken:
[HttpPost]
public Task<ActionResult<OrderDto>> CreateOrderAsync(
CreateOrderRequest request,
CancellationToken ct) =>
CustomerId.TryCreate(request.CustomerId)
.BindAsync(customerId => _customerService.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))
.ToActionResultAsync(this);
// Success: 200 OK with OrderDto
// Validation error: 400 Bad Request
// Customer not found: 404 Not Found
Remarks
This is the primary async method for converting domain results to HTTP responses. It awaits the result task and delegates to ToActionResult<TValue>(Result<TValue>, ControllerBase).
For performance-critical scenarios where the operation frequently completes synchronously, consider using the ValueTask overload instead.
CancellationToken Best Practice: The controller method should accept a CancellationToken parameter (ASP.NET Core automatically provides request cancellation) and pass it to all async service calls in the chain.
ToActionResultAsync<TValue>(Task<Result<TValue>>, ControllerBase, long, long, long)
Converts a Task-wrapped Result<TValue> to an ActionResult<TValue> with support for partial content responses using explicit range values.
public static Task<ActionResult<TValue>> ToActionResultAsync<TValue>(this Task<Result<TValue>> resultTask, ControllerBase controllerBase, long from, long to, long totalLength)
Parameters
resultTaskTask<Result<TValue>>The task containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
fromlongThe starting index of the range (inclusive, 0-based).
tolongThe ending index of the range (inclusive, 0-based).
totalLengthlongThe total number of items available.
Returns
- Task<ActionResult<TValue>>
A task that represents the asynchronous operation, containing:
- 206 Partial Content with Content-Range header if the range is a subset of the total
- 200 OK if the range represents the complete set
- Appropriate error status code if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Examples
[HttpGet]
public async Task<ActionResult<IEnumerable<UserDto>>> GetUsersAsync(
[FromQuery] int page = 0,
[FromQuery] int pageSize = 25)
{
var from = page * pageSize;
var to = from + pageSize - 1;
var totalCount = await _userService.GetTotalCountAsync();
return await _userService
.GetUsersAsync(from, pageSize)
.MapAsync(users => users.Select(u => new UserDto(u)))
.ToActionResultAsync(this, from, to, totalCount);
}
Remarks
Async variant of ToActionResult<TValue>(Result<TValue>, ControllerBase, long, long, long). Useful for async paginated queries where range values are computed separately.
ToActionResultAsync<TValue>(ValueTask<Result<TValue>>, ControllerBase)
Converts a ValueTask-wrapped Result<TValue> to an ActionResult<TValue> with appropriate HTTP status code.
public static ValueTask<ActionResult<TValue>> ToActionResultAsync<TValue>(this ValueTask<Result<TValue>> resultTask, ControllerBase controllerBase)
Parameters
resultTaskValueTask<Result<TValue>>The ValueTask containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
Returns
- ValueTask<ActionResult<TValue>>
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
[HttpGet("{id}")]
public ValueTask<ActionResult<UserDto>> GetUserAsync(Guid id) =>
UserId.TryCreate(id)
.BindAsync(_cacheService.GetUserAsync) // Returns ValueTask
.MapAsync(user => new UserDto(user))
.ToActionResultAsync(this);
Remarks
This overload is optimized for scenarios where the async operation frequently completes synchronously (e.g., cached results, in-memory operations). ValueTask can reduce allocations in these cases.
Use this when your service methods return ValueTask for performance optimization.
ToActionResultAsync<TValue>(ValueTask<Result<TValue>>, ControllerBase, long, long, long)
Converts a ValueTask-wrapped Result<TValue> to an ActionResult<TValue> with support for partial content responses using explicit range values (ValueTask variant).
public static ValueTask<ActionResult<TValue>> ToActionResultAsync<TValue>(this ValueTask<Result<TValue>> resultTask, ControllerBase controllerBase, long from, long to, long totalLength)
Parameters
resultTaskValueTask<Result<TValue>>The ValueTask containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
fromlongThe starting index of the range (inclusive, 0-based).
tolongThe ending index of the range (inclusive, 0-based).
totalLengthlongThe total number of items available.
Returns
- ValueTask<ActionResult<TValue>>
A ValueTask that represents the asynchronous operation, containing:
- 206 Partial Content with Content-Range header if the range is a subset
- 200 OK if the range represents the complete set
- Appropriate error status code if result is failure
Type Parameters
TValueThe type of the value contained in the result.
Remarks
ValueTask variant optimized for cached or frequently synchronous pagination scenarios.
ToActionResultAsync<TIn, TOut>(Task<Result<TIn>>, ControllerBase, Func<TIn, ContentRangeHeaderValue>, Func<TIn, TOut>)
Converts a Task-wrapped Result<TValue> to an ActionResult<TValue> with support for partial content responses (Task variant).
public static Task<ActionResult<TOut>> ToActionResultAsync<TIn, TOut>(this Task<Result<TIn>> resultTask, ControllerBase controllerBase, Func<TIn, ContentRangeHeaderValue> funcRange, Func<TIn, TOut> funcValue)
Parameters
resultTaskTask<Result<TIn>>The task containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
funcRangeFunc<TIn, ContentRangeHeaderValue>Function that extracts ContentRangeHeaderValue from the input value.
funcValueFunc<TIn, TOut>Function that transforms the input value to the output type.
Returns
- Task<ActionResult<TOut>>
A task that represents the asynchronous operation, containing:
- 206 Partial Content with Content-Range header if the range is a subset
- 200 OK if the range represents the complete set
- Appropriate error status code if result is failure
Type Parameters
TInThe type of the value contained in the input result.
TOutThe type of the value in the output ActionResult.
Examples
Async paginated endpoint:
[HttpGet]
public Task<ActionResult<IEnumerable<UserDto>>> GetUsersAsync(
[FromQuery] int page = 0,
[FromQuery] int pageSize = 25) =>
_userService
.GetPagedUsersAsync(page, pageSize)
.ToActionResultAsync(
this,
funcRange: result => new ContentRangeHeaderValue(
result.From, result.To, result.TotalCount),
funcValue: result => result.Items.Select(u => new UserDto(u))
);
// Returns 206 Partial Content with range headers for partial pages
// Returns 200 OK when all items fit in response
Remarks
Async variant of ToActionResult<TIn, TOut>(Result<TIn>, ControllerBase, Func<TIn, ContentRangeHeaderValue>, Func<TIn, TOut>). Useful for async paginated queries.
ToActionResultAsync<TIn, TOut>(ValueTask<Result<TIn>>, ControllerBase, Func<TIn, ContentRangeHeaderValue>, Func<TIn, TOut>)
Converts a ValueTask-wrapped Result<TValue> to an ActionResult<TValue> with support for partial content responses (ValueTask variant).
public static ValueTask<ActionResult<TOut>> ToActionResultAsync<TIn, TOut>(this ValueTask<Result<TIn>> resultTask, ControllerBase controllerBase, Func<TIn, ContentRangeHeaderValue> funcRange, Func<TIn, TOut> funcValue)
Parameters
resultTaskValueTask<Result<TIn>>The ValueTask containing the result object to convert.
controllerBaseControllerBaseThe controller context used to create the ActionResult.
funcRangeFunc<TIn, ContentRangeHeaderValue>Function that extracts ContentRangeHeaderValue from the input value.
funcValueFunc<TIn, TOut>Function that transforms the input value to the output type.
Returns
- ValueTask<ActionResult<TOut>>
A ValueTask that represents the asynchronous operation, containing:
- 206 Partial Content with Content-Range header if the range is a subset
- 200 OK if the range represents the complete set
- Appropriate error status code if result is failure
Type Parameters
TInThe type of the value contained in the input result.
TOutThe type of the value in the output ActionResult.
Remarks
ValueTask variant optimized for scenarios with cached or frequently synchronous results.