Immediate.Handlers
0.2.0
See the version list below for details.
dotnet add package Immediate.Handlers --version 0.2.0
NuGet\Install-Package Immediate.Handlers -Version 0.2.0
<PackageReference Include="Immediate.Handlers" Version="0.2.0" />
paket add Immediate.Handlers --version 0.2.0
#r "nuget: Immediate.Handlers, 0.2.0"
// Install Immediate.Handlers as a Cake Addin #addin nuget:?package=Immediate.Handlers&version=0.2.0 // Install Immediate.Handlers as a Cake Tool #tool nuget:?package=Immediate.Handlers&version=0.2.0
Immediate.Handlers
Immediate.Handlers is an implementation of the mediator pattern in .NET using source-generation. All pipeline behaviors are determined and the call-tree built at compile-time; meaning that all dependencies are enforced via compile-time safety checks. Behaviors and dependencies are obtained via DI at runtime based on compile-time determined dependencies.
Examples
- Minimal Api: Normal
Installing Immediate.Handlers
You can install Immediate.Handlers with NuGet:
Install-Package Immediate.Handlers
Or via the .NET Core command line interface:
dotnet add package Immediate.Handlers
Either commands, from Package Manager Console or .NET Core CLI, will download and install Immediate.Handlers.
Using Immediate.Handlers
Creating Handlers
Create a Handler by adding the following code:
[Handler]
public static class GetUsersQuery
{
public record Query;
private static ValueTask<IEnumerable<User>> HandleAsync(
Query _,
UsersService usersService,
CancellationToken token)
{
return usersService.GetUsers();
}
}
This will automatically create a new class, GetUsersQuery.Handler
, which encapsulates the following:
- attaching any behaviors defined for all queries in the assembly
- using a class to receive any DI services, such as
UsersService
Any consumer can now do the following:
public class Consumer(GetUsersQuery.Handler handler)
{
public async Task Consumer(CancellationToken token)
{
var response = await handler.HandleAsync(new(), token);
// do something with response
}
}
Creating Behaviors
Create a behavior by implementing the Immediate.Handlers.Shared.Behaviors<,>
class, as so:
public sealed class LoggingBehavior<TRequest, TResponse>(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
: Behavior<TRequest, TResponse>
{
public override async ValueTask<TResponse> HandleAsync(TRequest request, CancellationToken cancellationToken)
{
logger.LogInformation("LoggingBehavior.Enter");
var response = await Next(request, cancellationToken);
logger.LogInformation("LoggingBehavior.Exit");
return response;
}
}
This can be registered assembly-wide using:
[assembly: Behaviors(
typeof(LoggingBehavior<,>)
)]
or on an individual handler using:
[Handler]
[Behavior(
typeof(LoggingBehavior<,>)
)]
public static class GetUsersQuery
{
// ..
}
Once added to the pipeline, the behavior will be called as part of the pipeline to handle a request.
Note: adding a [Behavior]
attribute to a handler will disregard all assembly-wide behaviors for that handler, so any
global behaviors necessary must be independently added to the handler override behaviors list.
Behavior Constraints
A constraint can be added to a behavior by using:
public sealed class LoggingBehavior<TRequest, TResponse>
: Behavior<TRequest, TResponse>
where TRequest : IRequestConstraint
where TResponse : IResponseConstraint
When a pipeline is generated, all potential behaviors are evaluated against the request and response types, and if either type does not match a given constraint, the behavior is not added to the generated pipeline.
Registering with IServiceCollection
Immediate.Handlers supports Microsoft.Extensions.DependencyInjection.Abstractions
directly.
Registering Handlers
services.AddHandlers();
This registers all classes in the assembly marked with [Handler]
.
Registering Behaviors
services.AddBehaviors();
This registers all behaviors referenced in any [Behaviors]
attribute.
Performance Comparisons
All performance benchmarks reported use the following environment:
// * Summary *
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22621.3007/22H2/2022Update/SunValley2)
12th Gen Intel Core i7-12700H, 1 CPU, 20 logical and 14 physical cores
.NET SDK 8.0.101
[Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
Benchmarks.Simple
This benchmark tests the various mediator implementations with a single request/response handler.
Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen0 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
SendRequest_Baseline | 0.9303 ns | 0.0120 ns | 0.0113 ns | 1.00 | 0.00 | 1 | - | - | NA |
SendRequest_ImmediateHandler | 15.2625 ns | 0.0691 ns | 0.0646 ns | 16.41 | 0.19 | 2 | - | - | NA |
SendRequest_Mediator | 27.0657 ns | 0.1025 ns | 0.0959 ns | 29.10 | 0.33 | 3 | - | - | NA |
SendRequest_IMediator | 31.2996 ns | 0.0943 ns | 0.0882 ns | 33.65 | 0.43 | 4 | - | - | NA |
SendRequest_MediatR | 74.5688 ns | 1.1917 ns | 1.0564 ns | 80.12 | 1.77 | 5 | 0.0191 | 240 B | NA |
Benchmarks.Large
This benchmark tests the various mediator implementations in the face of 999 request/response handlers.
Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen0 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
SendRequest_Baseline | 0.9190 ns | 0.0272 ns | 0.0254 ns | 1.00 | 0.00 | 1 | - | - | NA |
SendRequest_ImmediateHandler | 15.4860 ns | 0.0990 ns | 0.0827 ns | 16.87 | 0.49 | 2 | - | - | NA |
SendRequest_Mediator | 27.7373 ns | 0.4364 ns | 0.4082 ns | 30.21 | 1.04 | 3 | - | - | NA |
SendRequest_MediatR | 79.6346 ns | 0.5683 ns | 0.4746 ns | 86.77 | 2.31 | 4 | 0.0191 | 240 B | NA |
SendRequest_IMediator | 429.8377 ns | 7.4163 ns | 6.9372 ns | 468.07 | 15.50 | 5 | - | - | NA |
Benchmarks.Behaviors
This benchmark tests a more realistic scenario of using 1 behavior and 1 service.
Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen0 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
SendRequest_Baseline | 54.90 ns | 0.177 ns | 0.166 ns | 1.00 | 0.00 | 1 | 0.0032 | 40 B | 1.00 |
SendRequest_ImmediateHandler | 78.11 ns | 0.286 ns | 0.268 ns | 1.42 | 0.01 | 2 | 0.0031 | 40 B | 1.00 |
SendRequest_Mediator | 96.94 ns | 0.268 ns | 0.224 ns | 1.77 | 0.01 | 3 | 0.0031 | 40 B | 1.00 |
SendRequest_IMediator | 106.64 ns | 0.588 ns | 0.550 ns | 1.94 | 0.01 | 4 | 0.0031 | 40 B | 1.00 |
SendRequest_MediatR | 198.24 ns | 0.860 ns | 0.718 ns | 3.61 | 0.02 | 5 | 0.0446 | 560 B | 14.00 |
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Immediate.Handlers:
Package | Downloads |
---|---|
Immediate.Validations
Source generated validations for Immediate.Handlers parameters. |
|
Immediate.Apis
A source generator to bind Immediate.Handlers handlers to minimal APIs. |
|
Immediate.Cache
A collection of classes that simplify caching responses from Immediate.Handlers handlers. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Immediate.Handlers:
Repository | Stars |
---|---|
SSWConsulting/SSW.VerticalSliceArchitecture
An enterprise ready solution template for Vertical Slice Architecture. This template is just one way to apply the Vertical Slice Architecture.
|
Version | Downloads | Last updated |
---|---|---|
2.0.0 | 371 | 11/13/2024 |
1.7.1 | 94 | 11/13/2024 |
1.7.0 | 871 | 10/12/2024 |
1.6.1 | 987 | 9/10/2024 |
1.6.0 | 98 | 9/9/2024 |
1.5.0 | 1,582 | 7/13/2024 |
1.4.0 | 2,789 | 5/4/2024 |
1.3.1 | 621 | 4/8/2024 |
1.3.0 | 530 | 3/25/2024 |
1.2.0 | 451 | 3/21/2024 |
1.1.0 | 793 | 2/5/2024 |
1.0.0 | 196 | 1/19/2024 |
0.5.0 | 106 | 1/16/2024 |
0.4.0 | 117 | 1/15/2024 |
0.3.0 | 100 | 1/15/2024 |
0.2.0 | 118 | 1/13/2024 |
0.1.0 | 140 | 1/10/2024 |
0.1.0-preview.0.160 | 71 | 1/9/2024 |