Search code examples
autofacmediatr

Why dont I need to call services.AddMediatr()?


I have an Web API application that uses both Mediatr and Autofac.

In my Startup.ConfigureServices method I have:

void ConfigureServices(IServiceCollection services)
{
    var executingAssembly = Assembly.GetExecutingAssembly();

    services.AddMediatR(executingAssembly);
}

In my Startup.ConfigureContainer() I have:

        builder.RegisterModule(new MediatorModule());
        builder.RegisterModule(new ApplicationModule("Connection String"));

In my MediatorModule based on Autofac I have:

    protected override void Load(ContainerBuilder builder)
{
    Guard.Against.Null(builder, nameof(builder));

    builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
        .AsImplementedInterfaces();

    // Register Repository class
    builder.RegisterAssemblyTypes(typeof(IJobSeekerRepository<JobSeeker>).GetTypeInfo().Assembly)
        .AsImplementedInterfaces();

    // Register Event Service
    builder.RegisterAssemblyTypes(typeof(IJobSeekerMgmtEventService).GetTypeInfo().Assembly)
            .AsImplementedInterfaces();

    // Commands Handlers
    builder.RegisterAssemblyTypes(typeof(AddCreditCardCommand).GetTypeInfo().Assembly)
        .AsClosedTypesOf(typeof(IRequestHandler<,>));

    // Domain Events 

builder.RegisterAssemblyTypes(typeof(JobSeekerRegisteredDomainEventRelayHandler).GetTypeInfo().Assembly)
        .AsClosedTypesOf(typeof(INotificationHandler<>));

    // Register Service Factory
    builder.Register<ServiceFactory>(context =>
    {
        var componentContext = context.Resolve<IComponentContext>();
        return t => { return componentContext.TryResolve(t, out var o) ? o : null; };
    });
}

And my ApplicationModule is:

    protected override void Load(ContainerBuilder builder)
    {
       builder.RegisterType(typeof(JobSeekerRepository<JobSeeker>))
        .As(typeof(IJobSeekerRepository<JobSeeker>))
        .InstancePerLifetimeScope();

       builder.RegisterType<RequestManager>()
         .As<IRequestManager>()
         .InstancePerLifetimeScope();

       builder.RegisterType<JobSeekerContextSeed>().InstancePerLifetimeScope();

       builder.RegisterType(typeof(JobSeekerMgmtEventService))
          .As(typeof(IJobSeekerMgmtEventService))
          .InstancePerLifetimeScope();

       // AddCreditCardCommand
       builder.RegisterType(typeof(IdentifiedCommandHandler<AddCreditCardCommand, CreditCardModel>))
              .As<IRequestHandler<IdentifiedCommand<AddCreditCardCommand, CreditCardModel>, CreditCardModel>>()
              .AsImplementedInterfaces();
    }

When I do the above and publish an event using Mediatr, it publishes the same event three times. So then I commented out the JobSeekerRegisteredDomainEventRelayHandler registration in MediatorModule. Once I did this then it only published the event twice.

I then commented out services.AddMediatr() and everything worked correctly - the event only got published once.

So now I am really confused - why does Mediatr still work even though I commented out AddMediatr()? Why did it publish the event twice when it is uncommented?


Solution

  • IMediatr is still available because you (also) register it via below call in your code.

    builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
        .AsImplementedInterfaces();
    

    The Mediatr GitHub wiki provides the steps to follow when e.g. using Autofac.
    There's also a full example which is using the code above to register IMediatr.

    That wiki shows you should make use of AddMediatr in case you're using the ASP.NET Core DI container, which you are not.


    You are also making multiple calls to Autofacs RegisterAssemblyTypes method, which is a scanning one, meaning it registers all types in the corresponding assembly.
    When you do that more than once for the same assembly, its IMediatr related types - e.g. command and notification handlers - fire more than once. Make sure to make that call only once per assembly.