Introduce compile-time registration capabilities with source generation, enabling automatic handler registration.
94 lines
3.1 KiB
Markdown
94 lines
3.1 KiB
Markdown
# `Geekeey.Request`
|
|
|
|
Simple mediator implementation in .NET with minimal dependencies.
|
|
|
|
## Features
|
|
|
|
- **Simple interfaces:** no complex constraints, just marker interfaces that work.
|
|
- **Minmal dependencies:** only depends on `Microsoft.Extensions.DependencyInjection.Abstractions` and the
|
|
`Microsoft.Extensions.Options` package.
|
|
|
|
## Getting Started
|
|
|
|
### Install the NuGet package:
|
|
|
|
```shell
|
|
dotnet add package Geekeey.Request
|
|
```
|
|
|
|
You may need to add our NuGet feed to your `nuget.config` this can be done by running the following command:
|
|
|
|
```shell
|
|
dotnet nuget add source -n geekeey https://code.geekeey.de/api/packages/geekeey/nuget/index.json
|
|
```
|
|
|
|
### Usage
|
|
|
|
```csharp
|
|
public static Task<int> Main()
|
|
{
|
|
var collection = new ServiceCollection();
|
|
collection.AddRequestDispatcher(builder => builder
|
|
.SearchHandlerInAssembly(typeof(ScalarHandler).Assembly)
|
|
.Add(typeof(ScalarBehavior)));
|
|
await using var provider = collection.BuildServiceProvider();
|
|
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
|
|
|
var request = new ScalarRequest { Value = "Hello" };
|
|
var result = await dispatcher.DispatchAsync(request);
|
|
|
|
Console.WriteLine(result);
|
|
return 0;
|
|
}
|
|
|
|
public class ScalarRequest : IScalarRequest<string>
|
|
{
|
|
public string Value { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class ScalarHandler : IScalarRequestHandler<ScalarRequest, string>
|
|
{
|
|
public Task<string> HandleAsync(ScalarRequest request, CancellationToken cancellationToken)
|
|
{
|
|
return Task.FromResult($"{request.Value} World");
|
|
}
|
|
}
|
|
|
|
public class ScalarBehavior : IScalarRequestBehavior<ScalarRequest, string>
|
|
{
|
|
public async Task<string> HandleAsync(ScalarRequest request, ScalarHandlerDelegate<string> next, CancellationToken cancellationToken)
|
|
{
|
|
Console.WriteLine("Before");
|
|
var result = await next(request, cancellationToken);
|
|
Console.WriteLine("After");
|
|
return result;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Compile-time registration
|
|
|
|
Projects that directly reference `Geekeey.Request` also get generated registration methods in the
|
|
`Geekeey.Request` namespace:
|
|
|
|
```csharp
|
|
collection.AddRequestDispatcher(builder => builder
|
|
.AddExampleProject()
|
|
.Add(typeof(ScalarBehavior)));
|
|
|
|
collection.AddRequestDispatcher(builder => builder
|
|
.AddExampleProject(ServiceLifetime.Scoped)
|
|
.Add(typeof(ScalarBehavior)));
|
|
```
|
|
|
|
- generation is enabled by default
|
|
- disable it with `<CompiletimeRequestDispatchHandlerRegistration>false</CompiletimeRequestDispatchHandlerRegistration>`
|
|
- rename the generated `Add<Name>(...)` methods with `CompiletimeRequestDispatchHandlerName`
|
|
- only request handlers are generated; behaviors still need normal registration
|
|
- nested request handlers are rejected during `Add(...)` registration, including `SearchHandlerInAssembly(...)` and by the source generator
|
|
- use one registration style per assembly: generated methods or `SearchHandlerInAssembly(...)`
|
|
|
|
## Behaviour of the Handlers
|
|
|
|
Handlers are resolved from either the DI container or are created on the fly but can receive arguments from the DI
|
|
container when being constructed. The same also applied for the request pipeline behaviours.
|