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?
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.