♻️ Move to Immediate.Handlers
viceroypenguin opened this issue · 10 comments
Immediate.Handlers is an improved way of dealing with the command/dispatch pattern; both for clarity of dependency relationship, and for performance.
Example VSA Template using it: https://github.com/viceroypenguin/VsaTemplate/tree/master/Web
Would love to hear your opinion on it, and whether you think it's useful for your template.
Hi @viceroypenguin, thanks for the issue :)
I've seen you link & talk about it on the discord, I've been meaning to check it out, and I will do so
I've triaged this to be in the next release :)
Awesome! If you wait another day or two, I'm also working on Immediate.Apis, which will automate registration of [Handler]
s that have [MapGet]
(or post, put, patch, delete) with Minimal APIs
Yeah I saw you release that, I believe theres a few source generated endpoint mappings. Whats the difference between Immediate.Apis
and the few examples below? Are both your Immediate
packages AOT compatible?
https://github.com/davidfowl/uController
https://github.com/joaofbantunes/RegisteringMinimalApisWithSourceGeneratorsSample
I assume it is the whole end to end of interface + wiring up to the generic host?
https://github.com/joaofbantunes/RegisteringMinimalApisWithSourceGeneratorsSample
I would recommend against this one generally because it uses ISourceGenerator
and hasn't been updated to IIncrementalGenerator
. There are some pretty steep performance differences between the two, which make anything still using ISourceGenerator
a disrecommendation.
Same for this one.
Goal of Immediate.Apis
Register the following:
using Immediate.Apis.Shared;
using Immediate.Handlers.Shared;
using Microsoft.AspNetCore.Authorization;
namespace Immediate.Apis.FunctionalTests.Features.WeatherForecast;
[Handler]
[MapGet("/forecast")]
[AllowAnonymous]
public static partial class Get
{
public sealed record Query;
public sealed record Result
{
public required DateOnly Date { get; init; }
public required int TemperatureC { get; init; }
public required string? Summary { get; init; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
private static async ValueTask<IReadOnlyList<Result>> Handle(
Query _,
CancellationToken token
)
{
await Task.Delay(1, token);
return [
new() { Date = new(2024, 1, 1), TemperatureC = 0, Summary = "Sunny and Freezing" },
];
}
}
by adding the following:
using Microsoft.AspNetCore.Mvc;
#pragma warning disable CS1591
namespace Microsoft.AspNetCore.Builder;
public static class ImmediateApisFunctionalTestsRoutesBuilder
{
public static IEndpointRouteBuilder MapImmediateApisFunctionalTestsEndpoints(
this IEndpointRouteBuilder app
)
{
_ = app
.MapGet(
"/forecast",
async (
[AsParameters] global::Immediate.Apis.FunctionalTests.Features.WeatherForecast.Get.Query parameters,
[FromServices] global::Immediate.Apis.FunctionalTests.Features.WeatherForecast.Get.Handler handler,
CancellationToken token
) => await handler.HandleAsync(parameters, token)
)
.AllowAnonymous()
;
return app;
}
}
I have not tested, but both should be AOT compatible, because there's no reflection or dynamic type analysis done.
Interesting - thank you for the example. I'll give this one a good look & try it out as well :)
BTW - if you're keen to contribute - I'd be happy to accept a PR moving from MediatR requests to Immediate.Handlers if you've got the time. Otherwise I'll action it myself
BTW - if you're keen to contribute - I'd be happy to accept a PR moving from MediatR requests to Immediate.Handlers if you've got the time. Otherwise I'll action it myself
I wish I did have the time. Unfortunately, I've got too many projects on my plate already, before I cursed myself by releasing two source generator projects. 😂
Besides, I need feedback from users other than myself on how well they work. :)
Perfect - I'll give you any feedback once I have a working version