fix(dispatcher): throw on ambiguous handlers instead of silent .First()
Multiple handlers for the same request were previously resolved via .First(), with ordering depending on Type.GetInterfaces() order (non-deterministic). Now ScalarRequestInvoker/StreamRequestInvoker throw InvalidOperationException listing the candidate handlers when more than one matches.
This commit is contained in:
parent
f7263c33a8
commit
f79e8780f7
7 changed files with 134 additions and 9 deletions
|
|
@ -7,6 +7,26 @@ namespace Geekeey.Request.Dispatcher.Tests;
|
|||
|
||||
public class StreamDispatcherTests
|
||||
{
|
||||
[Test]
|
||||
public async Task I_can_see_it_throw_on_ambiguous_stream_handlers()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(DuplicateStreamHandlerA))
|
||||
.Add(typeof(DuplicateStreamHandlerB)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new DuplicateStreamRequest();
|
||||
var ex = await Assert.That(async () => await dispatcher.DispatchAsync(request).ToListAsync()).Throws<InvalidOperationException>();
|
||||
|
||||
using (Assert.Multiple())
|
||||
{
|
||||
await Assert.That(ex?.Message).Contains(nameof(DuplicateStreamHandlerA));
|
||||
await Assert.That(ex?.Message).Contains(nameof(DuplicateStreamHandlerB));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_open_generic_handler()
|
||||
{
|
||||
|
|
@ -121,13 +141,18 @@ public class StreamDispatcherTests
|
|||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new InterfaceInheritedStreamRequest { Name = "Constrained" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
// Both InterfaceInheritedStreamHandler and InterfaceConstrainedStreamHandler could match.
|
||||
// InterfaceInheritedStreamHandler is a concrete match for InterfaceInheritedStreamRequest.
|
||||
// InterfaceConstrainedStreamHandler is an open generic match.
|
||||
// Currently Dispatcher checks concrete handlers first.
|
||||
await Assert.That(results).IsEquivalentTo(["Constrained-InterfaceHandled-0", "Constrained-InterfaceHandled-1"]);
|
||||
// Ambiguity is no longer resolved silently with .First(); it throws instead.
|
||||
var ex = await Assert.That(async () => await dispatcher.DispatchAsync(request).ToListAsync()).Throws<InvalidOperationException>();
|
||||
|
||||
using (Assert.Multiple())
|
||||
{
|
||||
await Assert.That(ex?.Message).Contains(nameof(InterfaceInheritedStreamHandler));
|
||||
await Assert.That(ex?.Message).Contains("InterfaceConstrainedStreamHandler");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue