martinothamar / Mediator

A high performance implementation of Mediator pattern in .NET using source generators.
MIT License
2.16k stars 71 forks source link

Support generic handlers #141

Closed Atulin closed 7 months ago

Atulin commented 8 months ago

I switched from MediatR to Mediator recently, for sourcegen instead of reflections. Alas, it doesn't seem to support generic handlers, and I have a specific use case for them:

public sealed record Command<T>(...) : IRequest<ActionResult> where T : BaseModel, IBlockableContent;

public class Handler<T>(ApplicationDbContext context) : BaseHandler, IRequestHandler<Command<T>, ActionResult>
    where T : BaseModel, IBlockableContent
{
    public async ValueTask<ActionResult> Handle(Command<T> request, CancellationToken cancellationToken)
    {
        // snip
        var res = await context.Set<T>() // here's where the generic is important
            .Where(i => i.Id == itemId)
            .ExecuteUpdateAsync(i => i.SetProperty(p => p.ContentBlock, cb), cancellationToken);
        // snip
    }
}
[HttpPost("story")]
public async Task<ActionResult> BlockStory(BlockContent.Command<Story> data)
    => await mediator.Send(data);

[HttpPost("chapter")]
public async Task<ActionResult> BlockChapter(BlockContent.Command<Chapter> data)
    => await mediator.Send(data);

[HttpPost("blogpost")]
public async Task<ActionResult> BlockBlogpost(BlockContent.Command<Blogpost> data)
    => await mediator.Send(data);
cranberry-clockworks commented 7 months ago

In MediatR one could register it by manually registering handler:

services.AddSingleton<IRequestHandler<Command<Story>, ActionResult>, Handler<Story>>();

But it doesn't seem to work in Mediator I'm still getting the error about handler not being found error.

martinothamar commented 7 months ago

True, doesn't support generic messages yet. Will require a refactoring of some things so not sure that will possible. I double checked, and it is documented in the "differences from MediatR" section in the readme: https://github.com/martinothamar/Mediator?tab=readme-ov-file#6-differences-from-mediatr

There is no support for manually registering message handlers, might be possible to change though, by checking the service collection before registering, though there may be more issues down the road..

The fundamental issue is that the sourcegen'd implementation is based around knowing concrete types, underlying handling functions need to namethem (it's not simply message.GetType())

martinothamar commented 7 months ago

Closing this and keeping track of #76