Обработчики не вызываются для некоторых уведомлений, опубликованных с помощью MediatR, в зависимости от иерархии классовC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Обработчики не вызываются для некоторых уведомлений, опубликованных с помощью MediatR, в зависимости от иерархии классов

Сообщение Anonymous »

Ниже вы найдете объяснение проблемы и простое, но почти полное воспроизведение (.Net 8 / MediatR 12.4.1), которое можно использовать в приложении Linqpad или консольном приложении.
У меня есть едва сложная иерархия классов уведомлений с MediatR:

Код: Выделить всё

public abstract class EntityNotification : INotification { }

public class EntityNotificationTyped : EntityNotification { }

public class A { }
public class B { }
(

Код: Выделить всё

INotification
-> EntityNotification -> EntityNotificationTyped). У меня есть и другие дочерние элементы под EntityNotificationTyped, но, как показано выше, этого уже достаточно, чтобы выявить проблему.
Обратите внимание, что «EntityNotification» сам по себе не является универсальным типом.
Вот обработчики:

Код: Выделить всё

public class GenericNotificationHandler
: INotificationHandler
{
public async Task Handle(EntityNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("GenericNotificationHandler received:" + notification.GetType().FullName);
}
}

public class EntityNotificationForAHandler
: INotificationHandler
{
public async Task Handle(EntityNotificationTyped notification, CancellationToken cancellationToken)
{
Console.WriteLine("EntityNotificationForAHandler received:" + notification.GetType().FullName);
}
}

public class EntityNotificationForBHandler
: INotificationHandler
{
public async Task Handle(EntityNotificationTyped notification, CancellationToken cancellationToken)
{
Console.WriteLine("EntityNotificationForBHandler received:" + notification.GetType().FullName);
}
}
Вот тестовая программа:

Код: Выделить всё

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddMediatR(config =>
{
config.RegisterServicesFromAssemblyContaining
();
});

var app = builder.Build();

var publisher = app.Services.GetRequiredService();

Console.WriteLine("Publishing A");
await publisher.Publish(new EntityNotificationTyped());

Console.WriteLine(Environment.NewLine + "Publishing B");
await publisher.Publish(new EntityNotificationTyped());

Console.WriteLine("End");
Если я запускаю его как есть, он работает нормально, все обработчики вызываются как положено:

Код: Выделить всё

Publishing A
GenericNotificationHandler received:EntityNotificationTyped`1[[A, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
EntityNotificationForAHandler received:EntityNotificationTyped`1[[A, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

Publishing B
GenericNotificationHandler received:EntityNotificationTyped`1[[B, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
EntityNotificationForBHandler received:EntityNotificationTyped`1[[B, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
End
Но теперь, если я полностью удалю класс «EntityNotificationForBHandler», для «Публикации B» не будет вызван обработчик:

Код: Выделить всё

Publishing A
GenericNotificationHandler received:EntityNotificationTyped`1[[A, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
EntityNotificationForAHandler received:EntityNotificationTyped`1[[A, MediatRPublish, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

Publishing B
End
Почему мой «GenericNotificationHandler», который раньше работал для любого типа уведомлений, не работает, когда нет специального обработчика для «наиболее вложенного наследуемого» типа уведомления, кроме того, он работает, когда последний присутствует?
Я заметил, что создание общего обработчика, похоже, помогает. Думаю, это как-то связано с ковариантностью/контравариантностью, но я не понимаю, почему иногда это работает, иногда нет. Вот возможный «обобщенный обработчик»:

Код: Выделить всё

public class GenericNotificationHandler(ILogger logger)
: INotificationHandler
where TEntityNotification : EntityNotification
{
public async Task Handle(TEntityNotification notification, CancellationToken cancellationToken)...
PS: Я также заметил, что если я явно регистрирую Generichandler для EntityNotificationTyped, это также работает: builder.Services.AddTransient();< /code> Но идея универсального обработчика заключалась в том, чтобы иметь возможность захватывать все виды уведомлений без необходимости их явной регистрации.
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/791 ... -depending
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»