jbogard / MediatR

Simple, unambitious mediator implementation in .NET
Apache License 2.0
11k stars 1.16k forks source link

Is there support for response types as tuples? #1052

Open digitalpacman opened 1 month ago

digitalpacman commented 1 month ago

I am looking to have the request return a tuple of (T, Common). However when implemented as a behavior, it appears to not match and execute. Looking around it looks like IPipelineBehavior only works when the generics are fixed as <T, T2> for the generics. I see everywhere that instead of IResult you want to use it as a constraint. However you can't use constraints for tuples like this.

I do not want to have to add this extra property to all my responses. But it looks like I'll have to build my own mediator pattern implementation, or switch to updating all my responses.

I would expect the bottom to output "Bar" but it outputs "Foo".


async Task Main()
{
    var services = new ServiceCollection();
    services.AddMediatR(cfg =>
    {
        cfg.RegisterServicesFromAssembly(this.GetType().Assembly);
        cfg.AddOpenBehavior(typeof(FooBehavior<,>));
    });
    var provider = services.BuildServiceProvider();
    var (response, common) = await provider.GetRequiredService<IMediator>().Send(new FooArgs());
    Console.WriteLine(response);
    Console.WriteLine(common);
}

public class FooBehavior<TRequest, TResponse>() : IPipelineBehavior<TRequest, (TResponse, BarCommon?)>
    where TResponse : class
{
    public Task<(TResponse, BarCommon?)> Handle(TRequest request, RequestHandlerDelegate<(TResponse, BarCommon?)> next, CancellationToken cancellationToken)
    {
        return Task.FromResult<(TResponse, BarCommon?)>(((TResponse)null, BarCommon.Bar));
    }
}

public class FooArgs : IRequest<(BarResponse, BarCommon?)>
{
}

public class FooHandler() : IRequestHandler<FooArgs, (BarResponse, BarCommon?)>
{
    public Task<(BarResponse, BarCommon?)> Handle(FooArgs request, CancellationToken cancellationToken)
    {
        return Task.FromResult<(BarResponse, BarCommon?)>(((BarResponse) null, BarCommon.Foo));
    }
}

public enum BarCommon
{
    Bar,
    Foo,
}
zachpainter77 commented 1 month ago

I'm pretty sure tuples as response types are fine.

I just tried this and it worked like a charm.

 public class TupleRequest : IRequest<(int TheInt, string TheString)>
 {
     public int TheInt { get; set; }
     public string? TheString { get; set; }
 }

 public class TupleRequestHandler : IRequestHandler<TupleRequest, (int, string)>
 {
     public Task<(int, string)> Handle(TupleRequest request, CancellationToken cancellationToken)
     {
         return Task.FromResult(( request.TheInt, request.TheString! ));
     }
 }
digitalpacman commented 1 month ago

The request handler worked but not the custom behavior

On Wed, Jul 24, 2024, 10:05 AM Zach Painter @.***> wrote:

I'm pretty sure tuples as response types are fine.

I just tried this and it worked like a charm.

public class TupleRequest : IRequest<(int TheInt, string TheString)> { public int TheInt { get; set; } public string? TheString { get; set; } }

public class TupleRequestHandler : IRequestHandler<TupleRequest, (int, string)> { public Task<(int, string)> Handle(TupleRequest request, CancellationToken cancellationToken) { return Task.FromResult(( request.TheInt, request.TheString! )); } }

— Reply to this email directly, view it on GitHub https://github.com/jbogard/MediatR/issues/1052#issuecomment-2248253212, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFMKV4XGSWS4BWBMACQ7ATZN67D3AVCNFSM6AAAAABLL3FZQWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENBYGI2TGMRRGI . You are receiving this because you authored the thread.Message ID: @.***>