From 993ca825967d834a5e031cfcdcfe4504aeb2ee1e Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 8 Apr 2026 14:01:24 +0200 Subject: [PATCH] Rename MediatR extensions to GetOrThrow for ISender Renamed SendOrThrowAsync and SendOrNotFoundAsync extension methods for IMediator to GetOrThrow for ISender, following MediatR best practices. Updated all usages, XML docs, and tests to use ISender and the new method names. Replaced StubMediator with StubSender in tests. Functionality remains the same, but code now aligns with modern MediatR conventions. --- .../Common/Extensions/MediatorExtensions.cs | 18 +-- .../Application/MediatorExtensionsTests.cs | 134 +++++++++--------- 2 files changed, 73 insertions(+), 79 deletions(-) diff --git a/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs b/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs index b0a09668..9a6a35dc 100644 --- a/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs +++ b/EnvelopeGenerator.Application/Common/Extensions/MediatorExtensions.cs @@ -15,16 +15,16 @@ public static class MediatorExtensions /// /// The expected response type. /// The exception type to throw. - /// The mediator instance. + /// 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) + public static async Task GetOrThrow(this ISender sender, IRequest request, Func exceptionFactory, CancellationToken cancel = default) where TException : Exception { - if (await mediator.Send(request, cancel) is TResponse res) + if (await sender.Send(request, cancel) is TResponse res) { if (res is not string && res is IEnumerable enumerable && !enumerable.Cast().Any()) throw exceptionFactory(); @@ -39,16 +39,16 @@ public static class MediatorExtensions /// Sends a request via MediatR and throws when the response is null or an empty collection. /// /// The expected response type. - /// The mediator instance. + /// The mediator instance. /// The MediatR request whose response may be null. /// Optional message for the . /// 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 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 GetOrThrow(this ISender sender, IRequest request, string? exceptionMessage, CancellationToken cancel = default) + => await sender.GetOrThrow(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 cancel = default) - => await mediator.SendOrNotFoundAsync(request, null, cancel); + /// + public static async Task GetOrThrow(this ISender sender, IRequest request, CancellationToken cancel = default) + => await sender.GetOrThrow(request, null, cancel); } \ No newline at end of file diff --git a/EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs b/EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs index ca28f61e..bec0c4a1 100644 --- a/EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs +++ b/EnvelopeGenerator.Tests/Application/MediatorExtensionsTests.cs @@ -12,13 +12,13 @@ public class MediatorExtensionsTests private sealed class StubRequest : IRequest { } /// - /// Minimal stub that returns a pre-configured response for any call. + /// Minimal stub that returns a pre-configured response for any call. /// - private sealed class StubMediator : IMediator + private sealed class StubSender : ISender { private readonly object? _response; - public StubMediator(object? response) => _response = response; + public StubSender(object? response) => _response = response; public Task Send(IRequest request, CancellationToken cancellationToken = default) { @@ -43,214 +43,208 @@ public class MediatorExtensionsTests public IAsyncEnumerable CreateStream(object request, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - - public Task Publish(object notification, CancellationToken cancellationToken = default) - => Task.CompletedTask; - - public Task Publish(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification - => Task.CompletedTask; } - private static IMediator CreateMediator(T? response) => new StubMediator(response); + private static ISender CreateSender(T? response) => new StubSender(response); #endregion - #region SendOrThrowAsync — non-null scalar + #region GetOrThrow — non-null scalar [Test] - public async Task SendOrThrowAsync_WithNonNullResponse_ReturnsResponse() + public async Task GetOrThrow_WithNonNullResponse_ReturnsResponse() { - var mediator = CreateMediator("hello"); + var sender = CreateSender("hello"); var request = new StubRequest(); - var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException()); + var result = await sender.GetOrThrow(request, () => new InvalidOperationException()); Assert.That(result, Is.EqualTo("hello")); } #endregion - #region SendOrThrowAsync — null response + #region GetOrThrow — null response [Test] - public void SendOrThrowAsync_WithNullResponse_ThrowsCustomException() + public void GetOrThrow_WithNullResponse_ThrowsCustomException() { - var mediator = CreateMediator(null); + var sender = CreateSender(null); var request = new StubRequest(); var ex = Assert.ThrowsAsync( - () => mediator.SendOrThrowAsync(request, () => new InvalidOperationException("custom"))); + () => sender.GetOrThrow(request, () => new InvalidOperationException("custom"))); Assert.That(ex!.Message, Is.EqualTo("custom")); } #endregion - #region SendOrThrowAsync — empty collection + #region GetOrThrow — empty collection [Test] - public void SendOrThrowAsync_WithEmptyList_ThrowsCustomException() + public void GetOrThrow_WithEmptyList_ThrowsCustomException() { - var mediator = CreateMediator>(new List()); + var sender = CreateSender>(new List()); var request = new StubRequest?>(); Assert.ThrowsAsync( - () => mediator.SendOrThrowAsync(request, () => new ArgumentException("empty"))); + () => sender.GetOrThrow(request, () => new ArgumentException("empty"))); } #endregion - #region SendOrThrowAsync — non-empty collection + #region GetOrThrow — non-empty collection [Test] - public async Task SendOrThrowAsync_WithNonEmptyList_ReturnsResponse() + public async Task GetOrThrow_WithNonEmptyList_ReturnsResponse() { var expected = new List { 1, 2 }; - var mediator = CreateMediator>(expected); + var sender = CreateSender>(expected); var request = new StubRequest?>(); - var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException()); + var result = await sender.GetOrThrow(request, () => new InvalidOperationException()); Assert.That(result, Is.EqualTo(expected)); } #endregion - #region SendOrThrowAsync — string edge case (string implements IEnumerable) + #region GetOrThrow — string edge case (string implements IEnumerable) [Test] - public async Task SendOrThrowAsync_WithEmptyString_ReturnsEmptyString() + public async Task GetOrThrow_WithEmptyString_ReturnsEmptyString() { - var mediator = CreateMediator(""); + var sender = CreateSender(""); var request = new StubRequest(); - var result = await mediator.SendOrThrowAsync(request, () => new InvalidOperationException("should not throw")); + var result = await sender.GetOrThrow(request, () => new InvalidOperationException("should not throw")); Assert.That(result, Is.EqualTo("")); } #endregion - #region SendOrNotFoundAsync — non-null scalar + #region GetOrThrow (NotFoundException) — non-null scalar [Test] - public async Task SendOrNotFoundAsync_WithNonNullResponse_ReturnsResponse() + public async Task GetOrThrow_NotFound_WithNonNullResponse_ReturnsResponse() { - var mediator = CreateMediator("hello"); + var sender = CreateSender("hello"); var request = new StubRequest(); - var result = await mediator.SendOrNotFoundAsync(request); + var result = await sender.GetOrThrow(request); Assert.That(result, Is.EqualTo("hello")); } [Test] - public async Task SendOrNotFoundAsync_WithExceptionMessage_AndNonNullResponse_ReturnsResponse() + public async Task GetOrThrow_NotFound_WithExceptionMessage_AndNonNullResponse_ReturnsResponse() { - var mediator = CreateMediator(42); + var sender = CreateSender(42); var request = new StubRequest(); - var result = await mediator.SendOrNotFoundAsync(request, "not found", CancellationToken.None); + var result = await sender.GetOrThrow(request, "not found", CancellationToken.None); Assert.That(result, Is.EqualTo(42)); } #endregion - #region SendOrNotFoundAsync — null response + #region GetOrThrow (NotFoundException) — null response [Test] - public void SendOrNotFoundAsync_WithNullResponse_ThrowsNotFoundException() + public void GetOrThrow_NotFound_WithNullResponse_ThrowsNotFoundException() { - var mediator = CreateMediator(null); + var sender = CreateSender(null); var request = new StubRequest(); - Assert.ThrowsAsync(() => mediator.SendOrNotFoundAsync(request)); + Assert.ThrowsAsync(() => sender.GetOrThrow(request)); } [Test] - public void SendOrNotFoundAsync_WithNullResponse_AndCustomMessage_ThrowsNotFoundExceptionWithMessage() + public void GetOrThrow_NotFound_WithNullResponse_AndCustomMessage_ContainsMessage() { const string message = "Entity not found"; - var mediator = CreateMediator(null); + var sender = CreateSender(null); var request = new StubRequest(); var ex = Assert.ThrowsAsync( - () => mediator.SendOrNotFoundAsync(request, message, CancellationToken.None)); + () => sender.GetOrThrow(request, message, CancellationToken.None)); Assert.That(ex!.Message, Does.Contain(message)); } [Test] - public void SendOrNotFoundAsync_WithNullResponse_HasDefaultMessage() + public void GetOrThrow_NotFound_WithNullResponse_HasDefaultMessageWithTypeName() { - var mediator = CreateMediator(null); + var sender = CreateSender(null); var request = new StubRequest(); - var ex = Assert.ThrowsAsync(() => mediator.SendOrNotFoundAsync(request)); + var ex = Assert.ThrowsAsync(() => sender.GetOrThrow(request)); Assert.That(ex!.Message, Does.Contain(nameof(String))); } #endregion - #region SendOrNotFoundAsync — empty collection + #region GetOrThrow (NotFoundException) — empty collection [Test] - public void SendOrNotFoundAsync_WithEmptyList_ThrowsNotFoundException() + public void GetOrThrow_NotFound_WithEmptyList_ThrowsNotFoundException() { - var mediator = CreateMediator>(new List()); + var sender = CreateSender>(new List()); var request = new StubRequest?>(); - Assert.ThrowsAsync(() => mediator.SendOrNotFoundAsync(request)); + Assert.ThrowsAsync(() => sender.GetOrThrow(request)); } [Test] - public void SendOrNotFoundAsync_WithEmptyArray_ThrowsNotFoundException() + public void GetOrThrow_NotFound_WithEmptyArray_ThrowsNotFoundException() { - var mediator = CreateMediator(Array.Empty()); + var sender = CreateSender(Array.Empty()); var request = new StubRequest(); - Assert.ThrowsAsync(() => mediator.SendOrNotFoundAsync(request)); + Assert.ThrowsAsync(() => sender.GetOrThrow(request)); } [Test] - public void SendOrNotFoundAsync_WithEmptyCollection_AndCustomMessage_ThrowsNotFoundExceptionWithMessage() + public void GetOrThrow_NotFound_WithEmptyCollection_AndCustomMessage_ContainsMessage() { const string message = "No items found"; - var mediator = CreateMediator>(new List()); + var sender = CreateSender>(new List()); var request = new StubRequest?>(); var ex = Assert.ThrowsAsync( - () => mediator.SendOrNotFoundAsync(request, message, CancellationToken.None)); + () => sender.GetOrThrow(request, message, CancellationToken.None)); Assert.That(ex!.Message, Does.Contain(message)); } #endregion - #region SendOrNotFoundAsync — non-empty collection + #region GetOrThrow (NotFoundException) — non-empty collection [Test] - public async Task SendOrNotFoundAsync_WithNonEmptyList_ReturnsResponse() + public async Task GetOrThrow_NotFound_WithNonEmptyList_ReturnsResponse() { var expected = new List { "a", "b" }; - var mediator = CreateMediator>(expected); + var sender = CreateSender>(expected); var request = new StubRequest?>(); - var result = await mediator.SendOrNotFoundAsync(request); + var result = await sender.GetOrThrow(request); Assert.That(result, Is.EqualTo(expected)); } [Test] - public async Task SendOrNotFoundAsync_WithNonEmptyArray_ReturnsResponse() + public async Task GetOrThrow_NotFound_WithNonEmptyArray_ReturnsResponse() { var expected = new[] { 1, 2, 3 }; - var mediator = CreateMediator(expected); + var sender = CreateSender(expected); var request = new StubRequest(); - var result = await mediator.SendOrNotFoundAsync(request); + var result = await sender.GetOrThrow(request); Assert.That(result, Is.EqualTo(expected)); } @@ -260,27 +254,27 @@ public class MediatorExtensionsTests #region CancellationToken [Test] - public void SendOrThrowAsync_WithCancelledToken_ThrowsOperationCanceledException() + public void GetOrThrow_WithCancelledToken_ThrowsOperationCanceledException() { - var mediator = CreateMediator("value"); + var sender = CreateSender("value"); var request = new StubRequest(); var cts = new CancellationTokenSource(); cts.Cancel(); Assert.ThrowsAsync( - () => mediator.SendOrThrowAsync(request, () => new InvalidOperationException(), cts.Token)); + () => sender.GetOrThrow(request, () => new InvalidOperationException(), cts.Token)); } [Test] - public void SendOrNotFoundAsync_WithCancelledToken_ThrowsOperationCanceledException() + public void GetOrThrow_NotFound_WithCancelledToken_ThrowsOperationCanceledException() { - var mediator = CreateMediator("value"); + var sender = CreateSender("value"); var request = new StubRequest(); var cts = new CancellationTokenSource(); cts.Cancel(); Assert.ThrowsAsync( - () => mediator.SendOrNotFoundAsync(request, cts.Token)); + () => sender.GetOrThrow(request, cts.Token)); } #endregion