Immediate.Handlers
0.4.0
See the version list below for details.
dotnet add package Immediate.Handlers --version 0.4.0
NuGet\Install-Package Immediate.Handlers -Version 0.4.0
<PackageReference Include="Immediate.Handlers" Version="0.4.0" />
paket add Immediate.Handlers --version 0.4.0
#r "nuget: Immediate.Handlers, 0.4.0"
// Install Immediate.Handlers as a Cake Addin #addin nuget:?package=Immediate.Handlers&version=0.4.0 // Install Immediate.Handlers as a Cake Tool #tool nuget:?package=Immediate.Handlers&version=0.4.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
}
}
In case your project layout does not allow direct for references between consumer and handler, the handler will also be
registered as an IHandler<TRequest, Response>
.
public class Consumer(IHandler<Query, IEnumerable<User>> 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 | Ratio | Rank | Allocated |
---|---|---|---|---|---|
SendRequest_Baseline | 0.7701 ns | 0.0180 ns | 1.00 | 1 | - |
SendRequest_IHandler | 15.6780 ns | 0.0476 ns | 20.36 | 2 | - |
SendRequest_ImmediateHandler | 16.6023 ns | 0.0561 ns | 21.56 | 3 | - |
SendRequest_Mediator | 27.2993 ns | 0.4269 ns | 35.49 | 4 | - |
SendRequest_IMediator | 31.3420 ns | 0.1006 ns | 40.64 | 5 | - |
SendRequest_MediatR | 68.3384 ns | 0.3453 ns | 88.73 | 6 | 240 B |
Benchmarks.Large
This benchmark tests the various mediator implementations in the face of 999 request/response handlers.
Method | Mean | Error | Ratio | Rank | Allocated |
---|---|---|---|---|---|
SendRequest_Baseline | 0.5656 ns | 0.0252 ns | 1.00 | 1 | - |
SendRequest_ImmediateHandler | 15.4346 ns | 0.0516 ns | 27.34 | 2 | - |
SendRequest_IHandler | 16.0959 ns | 0.0552 ns | 28.50 | 3 | - |
SendRequest_Mediator | 27.4104 ns | 0.0449 ns | 48.54 | 4 | - |
SendRequest_MediatR | 80.0953 ns | 0.4749 ns | 141.83 | 5 | 240 B |
SendRequest_IMediator | 435.3890 ns | 1.6399 ns | 771.01 | 6 | - |
Benchmarks.Behaviors
This benchmark tests a more realistic scenario of using 1 behavior and 1 service.
Method | Mean | Error | Ratio | Rank | Allocated |
---|---|---|---|---|---|
SendRequest_Baseline | 56.71 ns | 0.174 ns | 1.00 | 1 | 40 B |
SendRequest_IHandler | 78.90 ns | 0.304 ns | 1.39 | 2 | 40 B |
SendRequest_ImmediateHandler | 80.02 ns | 0.288 ns | 1.41 | 3 | 40 B |
SendRequest_Mediator | 101.23 ns | 0.263 ns | 1.78 | 4 | 40 B |
SendRequest_IMediator | 104.92 ns | 0.297 ns | 1.85 | 5 | 40 B |
SendRequest_MediatR | 201.27 ns | 1.023 ns | 3.55 | 6 | 560 B |
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 | 275 | 11/13/2024 |
1.7.1 | 81 | 11/13/2024 |
1.7.0 | 798 | 10/12/2024 |
1.6.1 | 967 | 9/10/2024 |
1.6.0 | 98 | 9/9/2024 |
1.5.0 | 1,547 | 7/13/2024 |
1.4.0 | 2,773 | 5/4/2024 |
1.3.1 | 621 | 4/8/2024 |
1.3.0 | 528 | 3/25/2024 |
1.2.0 | 448 | 3/21/2024 |
1.1.0 | 791 | 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 |