From 6c54473d5aa6a73dd9d7d1e26c8e105a9a252315 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 8 Apr 2026 13:44:19 +0200 Subject: [PATCH] Refactor MediatorExtensions for flexible exception handling Generalize null/empty response handling with SendOrThrowAsync, allowing custom exceptions via a factory delegate. SendOrNotFoundAsync now wraps this method for NotFoundException. Improves type safety, flexibility, and XML docs; avoids treating strings as collections. --- .../Common/Extensions/MediatorExtensions.cs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs b/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs index ea971903..b0a09668 100644 --- a/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs +++ b/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs @@ -9,6 +9,32 @@ namespace EnvelopeGenerator.Application.Common.Extensions; /// public static class MediatorExtensions { + /// + /// Sends a request via MediatR and throws a custom exception produced by + /// when the response is null or an empty collection. + /// + /// The expected response type. + /// The exception type to throw. + /// The mediator instance. + /// The MediatR request whose response may be null. + /// A factory that creates the exception to throw when the response is absent. + /// Cancellation token. + /// A guaranteed non-null . + /// The exception produced by . + public static async Task SendOrThrowAsync(this IMediator mediator, IRequest request, Func exceptionFactory, CancellationToken cancel = default) + where TException : Exception + { + if (await mediator.Send(request, cancel) is TResponse res) + { + if (res is not string && res is IEnumerable enumerable && !enumerable.Cast().Any()) + throw exceptionFactory(); + + return res; + } + + throw exceptionFactory(); + } + /// /// Sends a request via MediatR and throws when the response is null or an empty collection. /// @@ -16,23 +42,13 @@ public static class MediatorExtensions /// The mediator instance. /// The MediatR request whose response may be null. /// Optional message for the . - /// Cancellation token. + /// Cancellation token. /// A guaranteed non-null . /// Thrown when the response is null or an empty collection. - public static async Task SendOrNotFoundAsync(this IMediator mediator, IRequest request, string? exceptionMessage, CancellationToken cancellationToken = default) - { - if(await mediator.Send(request, cancellationToken) is TResponse res) - { - if(res is IEnumerable enumerable && !enumerable.Cast().Any()) - throw new NotFoundException(exceptionMessage); - - return res; - } - - throw new NotFoundException(exceptionMessage); - } + public static async Task SendOrNotFoundAsync(this IMediator mediator, IRequest request, string? exceptionMessage, CancellationToken cancel = default) + => await mediator.SendOrThrowAsync(request, () => new NotFoundException(exceptionMessage ?? $"The requested resource of type {typeof(TResponse).Name} was not found."), cancel); /// - public static async Task SendOrNotFoundAsync(this IMediator mediator, IRequest request, CancellationToken cancellationToken = default) - => await mediator.SendOrNotFoundAsync(request, null, cancellationToken); + public static async Task SendOrNotFoundAsync(this IMediator mediator, IRequest request, CancellationToken cancel = default) + => await mediator.SendOrNotFoundAsync(request, null, cancel); } \ No newline at end of file