Skip to main content

SendAll

SendAll executes multiple requests of the same response type in parallel using Task.WhenAll, returning all results as an array.

Signature

Task<TResponse[]> SendAll<TResponse>(IEnumerable<IRequest<TResponse>> requests, CancellationToken ct = default);

Basic Usage

var queries = new IRequest<Result<ProductDto>>[]
{
new GetProductQuery(id1),
new GetProductQuery(id2),
new GetProductQuery(id3),
};

Result<ProductDto>[] results = await _mediator.SendAll(queries);

foreach (var result in results)
{
if (result.IsSuccess)
Console.WriteLine(result.Value.Name);
}

Batch Processing

A common pattern is batch-processing a list of IDs:

public async Task<IActionResult> GetProductsBatch([FromBody] Guid[] productIds)
{
var queries = productIds.Select(id => new GetProductQuery(id));
Result<ProductDto>[] results = await _mediator.SendAll(queries);

var products = results
.Where(r => r.IsSuccess)
.Select(r => r.Value)
.ToList();

return Ok(products);
}

Comparison: SendAll vs Sequential Send

// Sequential — each waits for the previous
var results = new List<Result<ProductDto>>();
foreach (var id in productIds)
{
results.Add(await _mediator.Send(new GetProductQuery(id)));
}

// Parallel with SendAll — all requests start at the same time
Result<ProductDto>[] results = await _mediator.SendAll(
productIds.Select(id => new GetProductQuery(id)));

Performance

For N independent requests:

  • Sequential: total time ≈ sum of all handler times
  • SendAll: total time ≈ slowest individual handler
tip

Use SendAll when the requests are independent — they don't rely on each other's results.

warning

If any request's handler throws an unhandled exception (not a Result.Fail), SendAll will throw an AggregateException. Wrap handler logic in try/catch or use Result<T> to return errors as values.