MediatR icon indicating copy to clipboard operation
MediatR copied to clipboard

MediatR Design philosophy question

Open JoeMarkov opened this issue 3 years ago • 4 comments

In MediatR we define a command like:

public class Ping : IRequest<string> { }

and the corresponding handler like:

public class PingHandler : IRequestHandler<Ping, string>
{
    public Task<string> Handle(Ping request, CancellationToken cancellationToken)
    {
        return Task.FromResult("Pong");
    }
}

Awesome! But...

What is the reason why we need to provide the return type twice? (string in the example above)? Is it for a technical internal reason or for "readability/usability?"

Would it not be enough to provide it only in the IRequestHandler? or is it just for convenience to have it in both places?

JoeMarkov avatar Jun 01 '21 07:06 JoeMarkov

I think IRequest as a command, so need a response as a outcome, The simplest return is true or false. If you don't care response or result, you can inheritance INotification and INotificationHandler. See the following code, please

  /// <summary>
    /// Marker interface to represent a notification
    /// </summary>
    public interface INotification { }

    /// <summary>
    /// Defines a handler for a notification
    /// </summary>
    /// <typeparam name="TNotification">The type of notification being handled</typeparam>
    public interface INotificationHandler<in TNotification> where TNotification : INotification
    {
        /// <summary>
        /// Handles a notification
        /// </summary>
        /// <param name="notification">The notification</param>
        /// <param name="cancellationToken">Cancellation token</param>
        Task Handle(TNotification notification, CancellationToken cancellationToken);
    }

neozhu avatar Jun 01 '21 08:06 neozhu

thanks, yes, I know its a type of command, I was just more curious about why we need to have the return type in two places... that means I need to update two places when I want to change the return signature.

So, I just thought why is it not enough to have it IRequestHandler?

JoeMarkov avatar Jun 01 '21 08:06 JoeMarkov

I think this is certain rules for compile time validation.

neozhu avatar Jun 01 '21 08:06 neozhu

I think this is certain rules for compile time validation.

That is correct. It prevents you from creating a public class PingHandler : IRequestHandler<Ping, int> because Ping is a IRequest<string>.

One could argue that it doesn't actually work. There's nothing stopping me (at the API level) from defining a message as class Ping: IRequest<string>, IRequest<int> with the expectation that I'm allowed to create two request handlers and choose which I want to use when I invoke Send.

(I think there are runtime checks preventing this, but I'd have to read the code again to know for sure.)

Grauenwolf avatar Jul 29 '21 06:07 Grauenwolf