jbogard / MediatR

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

MediatR one notification handler #992

Closed Val9000 closed 3 months ago

Val9000 commented 8 months ago

So currently I have this scenario, where each handler will have 1:1 the same logic, so if i have 10 notifications / events that will mean I will also have 10 handler methods...

Smth like this

public Task Handle(TestResultTestParameterAdded notification, CancellationToken cancellationToken)
    => HandleTestResultEvent(notification, cancellationToken);

public Task Handle(TestResultTestParameterRemoved notification, CancellationToken cancellationToken)
    => HandleTestResultEvent(notification, cancellationToken);

public Task Handle(TestResultTestParameterValueChanged notification, CancellationToken cancellationToken)
    => HandleTestResultEvent(notification, cancellationToken);

public Task Handle(TestResultTestRemoved notification, CancellationToken cancellationToken)
    => HandleTestResultEvent(notification, cancellationToken);

public Task Handle(TestResultUnlinkedFromRequirement notification, CancellationToken cancellationToken)
    => HandleTestResultEvent(notification, cancellationToken);

public Task Handle(TestResultCustomExpectedResultCommentChanged notification, CancellationToken cancellationToken) 
    => HandleTestResultEvent(notification, cancellationToken);
    public interface ITestResultContextSubscriber :
          INotificationHandler<TestResultRenamed>,
          INotificationHandler<TestResultTestCreated>,
          INotificationHandler<TestResultTestCommentChanged>,
          INotificationHandler<TestResultTestConceptChanged>,
          INotificationHandler<TestResultTestParameterAdded>,
          INotificationHandler<TestResultTestParameterRemoved>,
          INotificationHandler<TestResultTestParameterValueChanged>,
          INotificationHandler<TestResultTestRemoved>,
          INotificationHandler<TestResultUnlinkedFromRequirement>
          {
          }

Is it possible to just have one Handler, and maybe 1 event that has it's own unqiue handler ??

TestResultRenamed and all the other events listed inherit from TestResultEvent, which, in turn, inherits from DomainEvent, and DomainEvent implements INotification from MediatR.

I have tried the follwing but the handle never gets called.

services.AddScoped<ITestResultContextSubscriber<TestResultEvent>, TestResultContextSubscriber>();

public interface ITestResultContextSubscriber<in T> :
    INotificationHandler<T> where T : TestResultEvent
{
}

public class TestResultContextSubscriber : ITestResultContextSubscriber<TestResultEvent>{

      public Task Handle(TestResultEvent notification, CancellationToken cancellationToken) =>
           HandleTestResultEvent(notification, cancellationToken);
}

Thanks in advance !

Shiney commented 8 months ago

Hello I may be misunderstanding your question but for me this code (as a program.cs) where I just create a non-generic INotificationHandler which implements INotificationHandler (which is my base event) seems to get called fine

using MediatR;
using Microsoft.Extensions.DependencyInjection;
using mytest;

// Create a new service collection and add mediatr
var services = new ServiceCollection();
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));

// Build the service provider
var serviceProvider = services.BuildServiceProvider();

using var scope = serviceProvider.CreateScope();
var mediatr = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediatr.Publish(new Notification1());
await mediatr.Publish(new Notification2());

internal record NotificationBase : INotification
{
}

internal record Notification1 : NotificationBase
{
}
internal record Notification2 : NotificationBase
{
}

internal class NotificationHandler1 : INotificationHandler<Notification1>
{
    public Task Handle(Notification1 notification, CancellationToken cancellationToken)
    {
        Console.WriteLine("NotificationHandler1");
        return Task.CompletedTask;
    }
}
internal class NotificationHandler2 : INotificationHandler<Notification2>
{
    public Task Handle(Notification2 notification, CancellationToken cancellationToken)
    {
        Console.WriteLine("NotificationHandler2");
        return Task.CompletedTask;
    }
}

internal class NotificationHandlerBase : INotificationHandler<NotificationBase>
{
    public Task Handle(NotificationBase notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"NotificationHandlerBase with {notification.ToString()}");
        return Task.CompletedTask;
    }
}

Works and I get the output below

NotificationHandler1
NotificationHandlerBase with Notification1 { }
NotificationHandler2
NotificationHandlerBase with Notification2 { }
jbogard commented 8 months ago

You're not awaiting anything. Publish returns a Task and needs to be awaited. It works in a console because of the disposing at the end of the execution.

Shiney commented 8 months ago

I've added the awaits to my answer.

FaridAhamat commented 8 months ago

Yes, I have the same problem. Notification solves 1-to-many handler problem, but the problem I have now is many events-to-1 handler. I've tried with playing around the event class' hierarchies, but some of my event just don't make sense from hierarchy point of view.

Any idea how to solve this?

jbogard commented 8 months ago

Events to one handler? Why not create separate handlers that depend on a common class?

zachpainter77 commented 6 months ago

The way to achieve what you're after is here: https://github.com/jbogard/MediatR/discussions/993#discussioncomment-8884584

github-actions[bot] commented 4 months ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

github-actions[bot] commented 3 months ago

This issue was closed because it has been stalled for 14 days with no activity.