jbogard / MediatR.Extensions.Microsoft.DependencyInjection

MediatR extensions for Microsoft.Extensions.DependencyInjection
MIT License
327 stars 89 forks source link

Getting strange behavior when registering an INotificationHandler<IIntegrationEvent> #89

Open cal5barton opened 3 years ago

cal5barton commented 3 years ago

Desired Behavior: Have a common handler for all events decorated with IIntegrationEvent interface without having to have a handler for each individual event.

Actual Behavior: Events decorated with IIntegrationEvent are not handled by the common IIntegrationEvent handler until the event has been handled at least one time explicitly in another handler.

public static IServiceProvider RegisterServices()
{
    var services = new ServiceCollection();
    //Register dependencies
    services.AddMediatR(typeof(IntegrationEventHandler)); // This is the common IIntegrationEventHandler

    return services.BuildServiceProvider(true);
}
public class IntegrationEventHandler : INotificationHandler<IIntegrationEvent>
{
    public Task Handle(IIntegrationEvent integrationEvent, CancellationToken cancellationToken)
    {
        //DO SOME WORK
        return Task.CompletedTask;
    }
}
public interface IIntegrationEvent : INotification
{
}

public class MyEvent : IIntegrationEvent
{
}

Will not work unless I have at least one handler that explicitly handles the MyEvent

public class ExplicitEventHandler : INotificationHandler<MyEvent>
{
    public Task Handle(MyEvent myEvent, CancellationToken cancellationToken)
    {
        //DO SOME WORK
        return Task.CompletedTask;
    }
}
garild commented 3 years ago

I also confirm that kind of issue.

I noticed that ServiceProvider doesn't contains any of type INotificationHandler<> in scope of request .

lilasquared commented 3 years ago

If you want to handle all notifications decorated with an interface I think the correct way to do that is using constrained generics

public class IntegrationEventHandler<TNotification> : INotificationHandler<TNotification> where TNotification : IIntegrationEvent
{
    public Task Handle(TNotification integrationEvent, CancellationToken cancellationToken)
    {
        //DO SOME WORK
        return Task.CompletedTask;
    }
}

If your service provider doesn't have the registered services then something is wrong with how you are using the registration code. The AddMediator extension accepts assembly parameters for which assemblies to scan for handlers.

cal5barton commented 3 years ago

If you want to handle all notifications decorated with an interface I think the correct way to do that is using constrained generics

public class IntegrationEventHandler : INotificationHandler<TNotification> where TNotification : IIntegrationEvent
{
    public Task Handle(TNotification integrationEvent, CancellationToken cancellationToken)
    {
        //DO SOME WORK
        return Task.CompletedTask;
    }
}

If your service provider doesn't have the registered services then something is wrong with how you are using the registration code. The AddMediator extension accepts assembly parameters for which assemblies to scan for handlers.

@lilasquared Your code doesn't compile when I replace the code that I have.

lilasquared commented 3 years ago

updated

garild commented 3 years ago

I think this kind of issue are basically depence on DI container.

Maybe is better to use Lamar or Garce

@cal5barton Can we close this issue ? ;)