Notification handlers resolved twice
See original GitHub issueReading past issues, this is a topic that showed up a couple of times and most often than not it was about registering types/assemblies twice.
Unfortunately this does not seem to be the case in our scenario.
What is more troubling is that we do get the correct behavior on a local windows
machine,
but not on a linux
docker container running the very same code.
Trying to simplify things as much as possible it boils down to this
- we send a
RemindCommand
that is handled by aRemindHandler
- when the handler completes it publishes a
RemindedEvent
to potential listeners - there are two notification handlers that listen, namely
RemindedAlert
andRemindedEmail
- therefore there is one
command
, onecommand handler
, oneevent
, twonotification handlers
- unfortunately
- while the
command handler
is invoked once - and the
event
is published once - each
notification handler
is invoked twice (!)
- while the
I suspected that there must have been double entries at IServiceCollection
level, but this was not the case.
Diagnosing the registered services everything shows up as expected on both windows
and linux
docker container
{
"results": [
{
"lifetime": "transient",
"contract": "MediatR.IRequestHandler`2[[Core.Domain.Remind.RemindCommand, Core.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Core.Domain.Remind.RemindResult, Core.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"implementation": "Core.Domain.Remind.RemindHandler"
},
{
"lifetime": "transient",
"contract": "MediatR.INotificationHandler`1[[Core.Contracts.RemindedEvent, Core.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"implementation": "Notifications.Module.RemindedAlert"
},
{
"lifetime": "transient",
"contract": "MediatR.INotificationHandler`1[[Core.Contracts.RemindedEvent, Core.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"implementation": "Notifications.Module.RemindedEmail"
}
]
}
Due to the size of the system things are split into several assemblies, but I suspect this should not matter much.
In the end in order to register the handlers we just rely on one of the AddMediatR
extension methods.
services.AddMediatR(new[]
{
typeof(IDomainModule),
typeof(IQueriesModule),
typeof(IAuditModule),
typeof(INotificationsModule),
...
});
While I am running out of ideas, I was wondering if maybe there is something obvious that I might have missed along the way…
Stack: .net: 6.0 mediatr: 10.0.1 os: centos
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
It turns out duplicate registrations were not that much of an issue, but it is more related with the way open generics were resolved to the unexpected handlers. Initially I was simply registering various application modules/dlls via the available conventions, and that seemed to work just fine.
Behind the scenes though there are a mix of open and closed types for
INotificationHandler<>
domain module
queries module
audit module
notifications module
the behavior I was witnessing was that
RemindedEvent
->RemindedAlert
handlerRemindedEvent
->RemindedEmail
handlerRemindedEvent
->ChangedHandler<T>
handler instead would somehow resolve to the same once more hence the double invocationRemindedEvent
->RemindedAlert
handlerRemindedEvent
->RemindedEmail
handlerTo correct the behavior, for the time being I ensured the open generics are defined explicitly. The only drawback would be that mixing manual registration with convention registration risks having multiple registrations in the container, therefore had to filter out those that were expected to have already been manually registered
This seems to have fixed the issue for now, and I might have missed something along the way, but I am still not sure how is it possible to observe it only when deployed to a docker container and not on a windows machine 😃
See the lesson here is to always use Windows everywhere /s