I have the following class hiarchy
public abstract class UserHasLeftTripEvent : INotification
{
}
public class PassengerHasLeftTripEvent : UserHasLeftLiveTripEvent
{
}
public class DriverHasLeftTripEvent : UserHasLeftLiveTripEvent
{
}
And then a handler that handles these notifications
public class UserHasLeftTripEventHandler : INotificationHandler<UserHasLeftTripEvent>
{
public async Task Handle(UserHasLeftTripEvent message, CancellationToken cancellationToken)
{
}
}
However when I publish my events using the following:
public List<INotification> domainEvents = new List<INotification>()
{
new DriverHasLeftTripEvent(),
new PassengerHasLeftTripEvent()
}
await Task.WhenAll(domainEvents.Select(async (ev) => { await _mediator.Publish(ev); }));
My events never reach my event handler. I'm assuming that I would need to actually publish UserHasLeftTripEvents for my handler to work? Is there any way to configure MediatR to use the derived classes?
try making your handler generic
public class UserHasLeftTripEventHandler<T> : INotificationHandler<T> where T : UserHasLeftTripEvent
Trying that right now and get the following exception on startup:
System.ArgumentException: 'Cannot instantiate implementation type 'LiveTripsApi.DomainEventHandlers.TripEvents.UserHasLeftTripEventHandler
1[T]' for service type 'MediatR.INotificationHandler1[T]'.'
can you share how you are registering the notification handlers? I'm not 100% sure on using them but I know that the pipeline behaviors are designed to be used as open generics.
I am not registering any of them. I am using .NET core and based on the tutorial I am following it is suggested to just include the MediatR.Extensions.Microsoft.DependencyInjection Nuget package. It has worked for my previous event handlers
If you make one that is specific to DriverHasLeftTripEvent does it work?
Yep just created two separate handlers for DriverHasLeftTrip and PassengerHasLeftTrip and both are being hit. So I mean not a big deal... I just have some duplication because both of these event handlers are doing the exact same thing. I liked the idea of using generics. It's unfortunate that I can't get it to work.
@JoshLefebvre There give this a shot - not the best but allows you to share the logic.
public abstract class UserHasLeftTripEventHandler<T> : INotificationHandler<T> where T : UserHasLeftTripEvent
{...}
public class PassengerHasLeftTripEventHandler : UserHasLeftTripEventHandler<PassengerHasLeftTripEvent>
{...}
public class DriverHasLeftTripEventHandler : UserHasLeftTripEventHandler<DriverHasLeftTripEvent>
{...}
that should do it for you
Just put all the logic on the abstract base class
I just ended up creating a service to add in my handler logic that I can call from both my event handlers so that solved my duplication issue. I appreciate your help!
Hi, I really would like to create a handler that handles a family of notifications. FOr example I want that all notifications that derive from a certain base class (which implements the INotification) to be forwarded to rabbitMQ or saved into a storage.
Having to create a derived handler is not a good option because besides the actual unnecessary class it forces me to add this for every new type of notification.
@bicatu can you create a new issue? I don't really monitor closed issues
sorry to comment on a closed issue, but was there a resolution to this or a new issue opened to track this?
I am looking to publish certain event messages derived from a base class for an audit log implementation. I don't want to create a handler for each event message, but rather to the specific base class for my auditing purposes. Currently, using MS Dependency Injection, and registering MediatR using the builtin extension method IServiceCollection.AddMediatR(Assembly[]).
I have verified that the handler works if I make it handle the specific event message, but if I make it handle the base class, then MediatR never dispatches to it.
Tagging @jbogard to make sure he sees this and can either point to another issue to follow up or a solution if any.
MS Dependency Injection doesn't support registering open generics. You will need to use a different DI.
@lilasquared that's not true, MediatR.Extensions.DI registers open generics. What is not supported (today) are generic constraints. However, my PR was merged so as of .NET 5, it will be.
@tafs7 if you're using the MediatR.Extensions.DI package, please raise the issue over there. MediatR here does not care how things are registered, it just uses IServiceProvider. Registration has nothing to do with this repo.
Ah yes my mistake. The constraints are the problem. Thanks for clarifying
Ok, I just tried this and it seemed to work - so disregard :)
public class AuditDomainEventHandler<T> : INotificationHandler<T> where T : AuditDomainEventBase
{
public Task Handle(T notification, CancellationToken cancellationToken)
{
Console.WriteLine($"handling event for {notification.Type}");
return Task.CompletedTask;
}
}
So what won't work is if you send a notification that is NOT that base type. You'll get an exception at runtime.
That's what my .NET 5 PR fixes. Or you must use another container.
On 9/3/2020 10:49:01 AM, Thiago Silva notifications@github.com wrote:
Ok, I just tried this and it seemed to work - so disregard :)
public class AuditDomainEventHandler
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub [https://github.com/jbogard/MediatR/issues/308#issuecomment-686583400], or unsubscribe [https://github.com/notifications/unsubscribe-auth/AAAZQMRAYZ32V7BCYISHHTDSD63G3ANCNFSM4FUXJZVA].
@tafs7 how did you manage your generic handler registration with MS ServiceCollection?
With the below lines:
services.AddScoped(typeof(IRequestHandler<>), typeof(ExampleHandler<>));
services.AddMediatR(typeof(Startup).Assembly);
It's working fine when implementing the INotificationHandler, which is good to publish events:
ExampleHandler<T> : INotificationHandler<T> where T : ExampleBaseCommand
usage: await _mediator.Publish(derivedCommand); =====> OK
but not with IRequestHandler, which is recommended to send commands:
ExampleHandler<T> : IRequestHandler<T> where T : ExampleBaseCommand
usage: await _mediator.Send(derivedCommand); =====> KO
@tafs7 how did you manage your generic handler registration with MS ServiceCollection?
With the below lines:
services.AddScoped(typeof(IRequestHandler<>), typeof(ExampleHandler<>)); services.AddMediatR(typeof(Startup).Assembly);It's working fine when implementing the INotificationHandler, which is good to publish events:
ExampleHandler<T> : INotificationHandler<T> where T : ExampleBaseCommandusage:
await _mediator.Publish(derivedCommand);=====> OKbut not with IRequestHandler, which is recommended to send commands:
ExampleHandler<T> : IRequestHandler<T> where T : ExampleBaseCommandusage:
await _mediator.Send(derivedCommand);=====> KO
For my use case, i was interested in publishing mediatr notifications only, since I was building an audit event mechanism. Don't think this would work for sending mediatr requests.
Most helpful comment
Hi, I really would like to create a handler that handles a family of notifications. FOr example I want that all notifications that derive from a certain base class (which implements the INotification) to be forwarded to rabbitMQ or saved into a storage.
Having to create a derived handler is not a good option because besides the actual unnecessary class it forces me to add this for every new type of notification.