question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IPipelineBehaviour with custom type for TResponse (ie. Result<TResponse>)

See original GitHub issue

I have several commands for which I want to apply cross-cutting concerns. The thing is, my handlers return Result<TResponse> and not just TResponse.

public readonly struct Result<T> { }
public class LoggingBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, Result<TResponse>> 
{
    public async Task<Result<TResponse>> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<Result<TResponse>> next)
    {
        Log.Information($"BEFORE");
        var response = await next();
        Log.Information($"AFTER");

        return response;
    }
}

// in Startup.cs
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>))

but I receive a run-time error when my commands are executed

An unhandled exception has occurred while executing the request.
System.ArgumentException: Implementation type LoggingBehaviour`2[Command1,Result[Response]]' can't be converted to service type 'MediatR.IPipelineBehavior`2[Command1,Result[Response]]'

I suppose my registration is not right, but can’t figure out how to do it properly.

Can you help me? Thanks!

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
lilasquaredcommented, Dec 4, 2019

I think there are issues with registering open generics on the default DI container for dotnet core - you may need to use a more advanced container. Here is my code using Simple Injector

class Program
{
    static async Task Main(string[] args)
    {
        var container = new Container();

        object Get(Type requestedType) => container.GetInstance(requestedType);

        container.Options.DefaultScopedLifestyle = new SimpleInjector.Lifestyles.AsyncScopedLifestyle();
        container.Options.DefaultLifestyle = Lifestyle.Transient;
        container.RegisterSingleton<IMediator>(() => new Mediator(Get));
        container.Collection.Register(typeof(IPipelineBehavior<,>), new[] 
        { 
            typeof(LoggingPipelineBehavior<,>) 
        });
        container.Register(typeof(IRequestHandler<,>), Assembly.GetExecutingAssembly());
        var bus = container.GetInstance<IMediator>();
        container.Verify();

        var res = await bus.Send(new WhatsTheTime());

        Console.WriteLine(res.Payload.Time);
        Console.ReadLine();
    }
}

public class LoggingPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, Result<TResponse>>
{
    public async Task<Result<TResponse>> Handle(
        TRequest request,
        CancellationToken cancellationToken,
        RequestHandlerDelegate<Result<TResponse>> next)
    {
        Console.WriteLine($"BEFORE");
        var response = await next();
        Console.WriteLine($"AFTER");

        return response;
    }
}

public class ThisIsTheTime
{
    public DateTime Time { get; }
    public ThisIsTheTime(DateTime dt) => Time = dt;
}

public class WhatsTheTime : IRequest<Result<ThisIsTheTime>> { }

public class WhatsTheTimeHandler : IRequestHandler<WhatsTheTime, Result<ThisIsTheTime>>
{
    public Task<Result<ThisIsTheTime>> Handle(WhatsTheTime request, CancellationToken cancellationToken)
    {
        return Task.FromResult(new Result<ThisIsTheTime>(new ThisIsTheTime(DateTime.UtcNow)));
    }
}

public readonly struct Result<T> {
    public readonly T Payload { get; }

    public Result(T payload)
    {
        Payload = payload;
    }
}
0reactions
lilasquaredcommented, Dec 4, 2019

here is the comment from jimmy on the issue - its not open generics but constrained open generics https://github.com/jbogard/MediatR/issues/305#issuecomment-417002645

not sure if this is the same as the exception you’re seeing though

Read more comments on GitHub >

github_iconTop Results From Across the Web

Response Caching with MediatR in ASP.NET Core
In this article, we are going to implement Response Caching with MediatR in ASP.NET Core using its awesome Pipeline Behaviours.
Read more >
MediatR IPipelineBehavior<TRequest, TResponse> errors ...
0.0 I started getting the below compilation error. The type 'TRequest' cannot be used as type parameter 'TRequest' in the generic type or...
Read more >
Advanced features of the MediatR package - Pipeline ...
The Handler processes the Request and returns a response back. ... The new class shall implement the IPipelineBehavior interface, ...
Read more >
CQRS and MediatR in ASP.NET Core
We first define a LoggingBehavior class, taking two types of parameters TRequest and TResponse , and implementing the IPipelineBehavior<TRequest ...
Read more >
MediatR Pipeline Examples
My authorization handler applies the former based on generic type (TRequest, TResponse) and the latter based on an attribute I add to my...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found