diff --git a/Directory.Packages.props b/Directory.Packages.props
index c22a3bf..a020c04 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,6 +6,7 @@
+
diff --git a/README.md b/README.md
index 30ebd7d..88eacb8 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ public static Task Main()
{
var collection = new ServiceCollection();
collection.AddRequestDispatcher(builder => builder
- .Add(typeof(ScalarHandler))
+ .SearchHandlerInAssembly(typeof(ScalarHandler).Assembly)
.Add(typeof(ScalarBehavior)));
await using var provider = collection.BuildServiceProvider();
var dispatcher = provider.GetRequiredService();
@@ -46,17 +46,17 @@ public class ScalarRequest : IScalarRequest
public string Value { get; set; } = string.Empty;
}
-public class ScalarHandler : IScalarRequestHandler
+public class ScalarHandler : IScalarRequestHandler
{
- public Task HandleAsync(ScalarTestRequest request, CancellationToken cancellationToken)
+ public Task HandleAsync(ScalarRequest request, CancellationToken cancellationToken)
{
return Task.FromResult($"{request.Value} World");
}
}
-public class ScalarBehavior : IScalarRequestBehavior
+public class ScalarBehavior : IScalarRequestBehavior
{
- public async Task HandleAsync(ScalarTestRequest request, ScalarHandlerDelegate next, CancellationToken cancellationToken)
+ public async Task HandleAsync(ScalarRequest request, ScalarHandlerDelegate next, CancellationToken cancellationToken)
{
Console.WriteLine("Before");
var result = await next(request, cancellationToken);
diff --git a/src/request.tests/Geekeey.Request.Tests.csproj b/src/request.tests/Geekeey.Request.Tests.csproj
index ec6ec2a..da5693e 100644
--- a/src/request.tests/Geekeey.Request.Tests.csproj
+++ b/src/request.tests/Geekeey.Request.Tests.csproj
@@ -9,6 +9,7 @@
+
diff --git a/src/request.tests/SearchHandlerInAssemblyTests.cs b/src/request.tests/SearchHandlerInAssemblyTests.cs
new file mode 100644
index 0000000..4ff15fb
--- /dev/null
+++ b/src/request.tests/SearchHandlerInAssemblyTests.cs
@@ -0,0 +1,124 @@
+// Copyright (c) The Geekeey Authors
+// SPDX-License-Identifier: EUPL-1.2
+
+using System.Collections;
+
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace Geekeey.Request.Tests;
+
+internal sealed class SearchHandlerInAssemblyTests
+{
+ [Test]
+ public async Task I_can_search_handlers_in_an_assembly()
+ {
+ const string source =
+ """
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Geekeey.Request;
+
+ namespace Sample;
+
+ public sealed class Ping : IScalarRequest
+ {
+ }
+
+ public sealed class PingHandler : IScalarRequestHandler
+ {
+ public Task HandleAsync(Ping request, CancellationToken cancellationToken) => Task.FromResult("pong");
+ }
+ """;
+ using var assembly = DynamicTestAssembly.Compile(source);
+
+ var services = new ServiceCollection();
+ services.AddRequestDispatcher(builder => builder
+ .SearchHandlerInAssembly(assembly.Assembly));
+ await using var provider = services.BuildServiceProvider();
+ var options = provider.GetRequiredService>().Value;
+ var requestType = assembly.Assembly.GetType("Sample.Ping", throwOnError: true)!;
+ var handlerType = assembly.Assembly.GetType("Sample.PingHandler", throwOnError: true)!;
+ var handlerInterface = typeof(IScalarRequestHandler<,>).MakeGenericType(requestType, typeof(string));
+ var handlers = GetRequestHandlers(options, handlerInterface, provider).ToArray();
+
+ using var scope = Assert.Multiple();
+ await Assert.That(handlers).Count().IsEqualTo(1);
+ await Assert.That(handlers.Single()!.GetType()).IsEqualTo(handlerType);
+ }
+
+ [Test]
+ public async Task I_can_search_handlers_in_an_assembly_with_a_lifetime()
+ {
+ const string source =
+ """
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Geekeey.Request;
+
+ namespace Sample;
+
+ public sealed class Ping : IScalarRequest
+ {
+ }
+
+ public sealed class PingHandler : IScalarRequestHandler
+ {
+ public Task HandleAsync(Ping request, CancellationToken cancellationToken) => Task.FromResult("pong");
+ }
+ """;
+ using var assembly = DynamicTestAssembly.Compile(source);
+
+ var services = new ServiceCollection();
+ services.AddRequestDispatcher(builder => builder
+ .SearchHandlerInAssembly(assembly.Assembly, ServiceLifetime.Singleton));
+ var handlerType = assembly.Assembly.GetType("Sample.PingHandler", throwOnError: true)!;
+ var descriptor = services.SingleOrDefault(service => service.ServiceType == handlerType);
+
+ using var scope = Assert.Multiple();
+ await Assert.That(descriptor).IsNotNull();
+ await Assert.That(descriptor!.Lifetime).IsEqualTo(ServiceLifetime.Singleton);
+ }
+
+ [Test]
+ public async Task I_get_an_exception_when_nested_handlers_are_present()
+ {
+ const string source =
+ """
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Geekeey.Request;
+
+ namespace Sample;
+
+ public sealed class Ping : IScalarRequest
+ {
+ }
+
+ public sealed class Container
+ {
+ public sealed class PingHandler : IScalarRequestHandler
+ {
+ public Task HandleAsync(Ping request, CancellationToken cancellationToken) => Task.FromResult("pong");
+ }
+ }
+ """;
+ using var assembly = DynamicTestAssembly.Compile(source);
+
+ var services = new ServiceCollection();
+ var builder = services.AddRequestDispatcher();
+
+ await Assert.That(() => builder.SearchHandlerInAssembly(assembly.Assembly))
+ .Throws().And.HasMessageContaining("Sample.Container+PingHandler");
+ }
+
+ private static IEnumerable