RSCG – Immediate.Handlers
Generating mediator like handlers
This is how you can use Immediate.Handlers .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Immediate.Handlers" Version="1.6.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
</ItemGroup>
</Project>
The code that you will use is
Console.WriteLine("Hello, World!");
ServiceCollection services = new ();
services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(NullLogger<>));
services.AddHandlers();
services.AddBehaviors();
IHandler<Ping, Pong> handler = services.BuildServiceProvider().GetRequiredService<IHandler<Ping, Pong>>();
var id = Guid.NewGuid();
var request = new Ping(id);
var pong = await handler.HandleAsync(request, CancellationToken.None);
Console.WriteLine($"Got pong with id {pong.Id}!");
using Immediate.Handlers.Shared;
public sealed record Ping(Guid Id);// : IRequest<Pong>;
public sealed record Pong(Guid Id);
[Handler]
[Behaviors(
typeof(LoggingBehavior<,>)
)]
public static partial class PingHandler //: IPipelineAction<Ping, Pong>
{
private static async ValueTask<Pong> HandleAsync(Ping request, CancellationToken token)
{
await Task.Delay(1000);
Console.WriteLine("Returning pong!");
return new Pong(request.Id);
}
}
public sealed class LoggingBehavior<TRequest, TResponse>(ILogger<LoggingBehavior<TRequest, TResponse>>? logger)
: Behavior<TRequest, TResponse>
{
public override async ValueTask<TResponse> HandleAsync(TRequest request, CancellationToken cancellationToken)
{
Console.WriteLine("I am a logging behaviour");
logger?.LogInformation("LoggingBehavior.Enter");
var response = await Next(request, cancellationToken);
logger?.LogInformation("LoggingBehavior.Exit");
return response;
}
}
global using Microsoft.Extensions.DependencyInjection;
global using Immediate.Handlers.Shared;
global using Microsoft.Extensions.Logging;
global using Mediator;
global using Microsoft.Extensions.Logging.Abstractions;
The code that is generated is
using Microsoft.Extensions.DependencyInjection;
#pragma warning disable CS1591
partial class PingHandler
{
public sealed partial class Handler : global::Immediate.Handlers.Shared.IHandler<global::Ping, global::Pong>
{
private readonly global::PingHandler.HandleBehavior _handleBehavior;
private readonly global::LoggingBehavior<global::Ping, global::Pong> _loggingBehavior;
public Handler(
global::PingHandler.HandleBehavior handleBehavior,
global::LoggingBehavior<global::Ping, global::Pong> loggingBehavior
)
{
var handlerType = typeof(PingHandler);
_handleBehavior = handleBehavior;
_loggingBehavior = loggingBehavior;
_loggingBehavior.HandlerType = handlerType;
_loggingBehavior.SetInnerHandler(_handleBehavior);
}
public async global::System.Threading.Tasks.ValueTask<global::Pong> HandleAsync(
global::Ping request,
global::System.Threading.CancellationToken cancellationToken = default
)
{
return await _loggingBehavior
.HandleAsync(request, cancellationToken)
.ConfigureAwait(false);
}
}
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class HandleBehavior : global::Immediate.Handlers.Shared.Behavior<global::Ping, global::Pong>
{
public HandleBehavior(
)
{
}
public override async global::System.Threading.Tasks.ValueTask<global::Pong> HandleAsync(
global::Ping request,
global::System.Threading.CancellationToken cancellationToken
)
{
return await global::PingHandler
.HandleAsync(
request
, cancellationToken
)
.ConfigureAwait(false);
}
}
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public static IServiceCollection AddHandlers(
IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
services.Add(new(typeof(global::PingHandler.Handler), typeof(global::PingHandler.Handler), lifetime));
services.Add(new(typeof(global::Immediate.Handlers.Shared.IHandler<global::Ping, global::Pong>), typeof(global::PingHandler.Handler), lifetime));
services.Add(new(typeof(global::PingHandler.HandleBehavior), typeof(global::PingHandler.HandleBehavior), lifetime));
return services;
}
}
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
#pragma warning disable CS1591
namespace Mediator;
public static class HandlerServiceCollectionExtensions
{
public static IServiceCollection AddBehaviors(
this IServiceCollection services)
{
services.TryAddTransient(typeof(global::LoggingBehavior<,>));
return services;
}
public static IServiceCollection AddHandlers(
this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
global::PingHandler.AddHandlers(services, lifetime);
return services;
}
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Immediate.Handlers