为什么我不需要调用 services.AddMediatr()?
我有一个同时使用 Mediatr 和 Autofac 的 Web API 应用程序。
在我的 Startup.ConfigureServices 方法中,我有:
void ConfigureServices(IServiceCollection services)
{
var executingAssembly = Assembly.GetExecutingAssembly();
services.AddMediatR(executingAssembly);
}
在我的 Startup.ConfigureContainer() 中,我有:
builder.RegisterModule(new MediatorModule());
builder.RegisterModule(new ApplicationModule("Connection String"));
在基于 Autofac 的 MediatorModule 中,我有:
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; };
});
}
我的 ApplicationModule 是:
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();
}
当我执行上述操作并使用 Mediatr 发布事件时,它会发布相同的事件三次。所以然后我注释掉了MediatorModule中的JobSeekerRegisteredDomainEventRelayHandler注册。一旦我这样做了,它就只发布了该事件两次。
然后我注释掉 services.AddMediatr() 并且一切正常 - 该事件仅发布一次。
所以现在我真的很困惑 - 为什么 Mediatr 仍然有效,即使我注释掉了 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
IMediatr
仍然可用,因为您(也)通过代码中的以下调用注册它。Mediatr
GitHub wiki 提供了以下情况下要遵循的步骤:使用Autofac
。还有一个完整的 示例使用上面的代码来注册
IMediatr
。该 wiki 显示您应该使用
AddMediatr
如果您使用 ASP.NET Core DI 容器,但你不是。您还多次调用 Autofacs
RegisterAssemblyTypes
方法,该方法是 扫描一个,这意味着它会注册相应程序集中的所有类型。当您对同一程序集多次执行此操作时,其
IMediatr
相关类型(例如命令和通知处理程序)会多次触发。确保每个程序集仅调用一次。
IMediatr
is still available because you (also) register it via below call in your code.The
Mediatr
GitHub wiki provides the steps to follow when e.g. usingAutofac
.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.