Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MissingMessageHandlerException when passing derived class to Send #100

Open
Xpl0itR opened this issue Jun 23, 2023 · 4 comments
Open

MissingMessageHandlerException when passing derived class to Send #100

Xpl0itR opened this issue Jun 23, 2023 · 4 comments

Comments

@Xpl0itR
Copy link

Xpl0itR commented Jun 23, 2023

I understand why this doesn't work, but would it be possible to implement support for this?

This is my use-case:

In domain project (with Mediator.Abstractions)

public interface IMyReq : IRequest<string>
{
    string MyParam { get; }
}

public sealed class MyReqHandler : IRequestHandler<IMyReq, string>
{
    // implementation...
    public ValueTask<string> Handle(IMyReq req, CancellationToken ct)
    {
        // implementation...
    }
}

In asp.net application project (with Mediator.SourceGenerator)

public sealed record MyReq : IMyReq
{
    [FromQuery]
    public required string MyParam { get; init; }
}

public static partial class Endpoints
{
    public static void MapEndpoints(this IEndpointRouteBuilder endpoints)
    {
        endpoints.MapGet("/my_endpoint", (IMediator mediator, [AsParameters] MyReq req) => mediator.Send((IMyReq)req));
        // ...
    }
}
@CheloXL
Copy link

CheloXL commented Jun 24, 2023

Mmm.. I don't think that's the problem. First because records are classes (unless it's a struct record). Second, because I'm already using records as commands and it works just fine.
So, the issue must be anything else, maybe related to the use of an interface?

@Xpl0itR
Copy link
Author

Xpl0itR commented Jun 24, 2023

I believe feiyun0112 is correct, but it would be nice to support interfaces or abstract classes

@martinothamar
Copy link
Owner

Even if the source generator filters out the interface itself (like @feiyun0112 says), it still is able to find the concrete requests deriving from IMyReq, but the source generator doesn't currently match it with a handler, since it expects the type parameters to match. There might be a way to make the source generator support this, when doing the message -> handler matching, use the most concrete message/handler combination where possible, but I'm not sure if it's worth it.

I guess the practical difference in the end would be

public sealed class MyReqHandler : IRequestHandler<IMyReq, string>
{
    public ValueTask<string> Handle(IMyReq req, CancellationToken ct)
    {
        switch (req)
        {
            // ...
        }
    }
}

vs

public sealed class ConcreteReq1Handler : IRequestHandler<ConcreteReq1, string>
{
    public ValueTask<string> Handle(ConcreteReq1 req, CancellationToken ct)
    {    }
}
public sealed class ConcreteReq2Handler : IRequestHandler<ConcreteReq2, string>
{
    public ValueTask<string> Handle(ConcreteReq2 req, CancellationToken ct)
    {    }
}

So I think the implementation and maintenance cost outweigh the benefit in this case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants