jbogard/MediatR

Is there support for response types as tuples?

digitalpacman opened this issue · 4 comments

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,
}

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! ));
     }
 }