Search code examples
c#asp.netmediatr

MediatR: INotification handler is being called multiple times


I'm using MediatR 9.0.0 (with MediatR.Extensions.Microsoft.DependencyInjection 9.0.0). I have event notification handler like that:

public class StatusChangedEventHandler : INotificationHandler<StatusChangedEvent>
{
    
   public StatusChangedEventHandler ()
   {
   }
    
   public async Task Handle(StatusChangedEvent evnt, CancellationToken cancellationToken)
   {
      //some code 
   }
}

The event is being published from another command handler:

public class ChangeStatusCommandHandler : IRequestHandler<ChangeStatusCommand, bool>
    {
        ...
        private readonly IMediator _mediator;

        public ChangeStatusCommandHandler(...,IMediator mediator)
        {
            ...
            _mediator = mediator;
        }

        public async Task<bool> Handle(ChangeStatusCommand command, CancellationToken cancellationToken)
        {

            ...

            await _mediator.Publish(new StatusChangedEvent(int id, string message));

            ...
            
        }
    }

The problem is StatusChangedEventHandler.Handle method is being called multiple times - I noticed it seems to be relative to number of command handlers registered in Startup.cs, e.g.

services.AddMediatR(typeof(CommandA));

=> the handler would be called once

services.AddMediatR(typeof(CommandA));
services.AddMediatR(typeof(CommandB));

=> the handler would be called twice

services.AddMediatR(typeof(CommandA));
services.AddMediatR(typeof(CommandB));
services.AddMediatR(typeof(CommandC));

=> the handler would be called 3 time etc.

How to fix that to make handler being called just once?


Solution

  • A call to services.AddMediatR(typeof(CommandA)) doesn't only register that single command handler CommandA, it registers all command handlers that are present in the assembly containing CommandA; the full assembly is being scanned for its handlers.

    From the documentation

    Scans assemblies and adds handlers, preprocessors, and postprocessors implementations to the container. To use, with an IServiceCollection instance:

    You must not explicitly call AdMediatR upon the other command handlers; remove the ones below.

    services.AddMediatR(typeof(CommandB));
    services.AddMediatR(typeof(CommandC));