Обработчики запускаются несколько раз для одного и того же уведомления, но автоматическое подключение работает должным образом

#c# #.net-core #structuremap #mediatr

#c# #.net-core #structuremap #mediatr

Вопрос:

У меня есть ASP.NET Ядро 3.1 со StructureMap и Mediatr.

Раньше, когда я использовал контейнер DI по умолчанию, мой дочерний обработчик запускался дважды. Функциональность там довольно ограничена, поэтому я переключился на StructureMap. Но все же, когда я применяю разные настройки к сканеру, я не могу получить ожидаемое поведение. Это либо базовый, либо дочерний обработчик, выполняемый дважды, либо оба. Единственный рабочий случай заключается в том, что я ничего не указываю typeof(INotificationHandler<>) , все работает нормально из-за автоматического подключения (возможно?), Но я чувствую, что между вызовами обработчика уведомлений есть задержка, поэтому я хотел бы правильно настроить контейнер при запуске приложения.

Мои уведомления и обработчики уведомлений приведены ниже. Ожидаемое поведение: при публикации дочернего уведомления запускаются оба обработчика один раз

 public class ApplicationUserRegisteredNotification : INotification
{
    public ApplicationUser User { get; }

    public ApplicationUserRegisteredNotification(ApplicationUser user)
    {
        User = user;
    }
}

public class SpecificUserRegisteredNotification : ApplicationUserRegisteredNotification
{
    public SpecificUserProfile SpecificUser { get; }

    public SpecificUserRegisteredNotification(SpecificUserProfile specificUser)
        : base(specificUser.User)
    {
        SpecificUser = specificUser;
    }
}

public class SendEmailConfirmationEmail : INotificationHandler<ApplicationUserRegisteredNotification>
{
    // some code
}
public class SendAdminVerifySpecificUserRegistration : INotificationHandler<SpecificUserRegisteredNotification>
{
    // some code
}
  

Я использую StructureMap.AspNetCore для создания IServiceProvider , какой вариант я мог бы использовать для явного применения логики автоматического подключения? В комментариях ниже вы можете увидеть выходные данные для каждого параметра.

 public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // some code
    var container = new Container(cfg =>
    {
        cfg.Scan(scanner =>
        {
            scanner.AssemblyContainingType(GetType());
            scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<>));
            scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
            //scanner.ConnectImplementationsToTypesClosing(typeof(INotificationHandler<>)); // both handlers triggered twice in given sequence: base, child, base, child
            //scanner.AddAllTypesOf(typeof(INotificationHandler<>)); // both handlers triggered in given sequence: base, base, child
            // nothing: everything works as expected - base, child, but switching between handlers is rather slow
        });
    });

    container.Populate(services);

    return container.GetInstance<IServiceProvider>();
}
  

Program.cs

 public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStructureMap()
            .UseStartup<Startup>();
}
  

До StructureMap моя конфигурация выглядела так

 services.AddTransient<INotificationHandler<SpecificUserRegisteredNotification>, SendEmailConfirmationEmail>();               
    services.AddTransient<INotificationHandler<OtherSpecificUserRegisteredNotification>, SendEmailConfirmationEmail>();
    services.AddTransient<IRequestHandler<RegisterSpecificCommand, BaseCommandResponse>, RegisterApplicationUserCommandHandler>();
    services.AddTransient<IRequestHandler<RegisterOtherSpecificCommand, BaseCommandResponse>, RegisterApplicationUserCommandHandler>();
  

Ответ №1:

используйте:

 services.AddMediatR(AppDomain.CurrentDomain.Load("AssemblyName"));

  

зарегистрируйте свои обработчики в обычном режиме. Пример:

 services.AddTransient<INotificationHandler<SpecificUserRegisteredNotification>, SendEmailConfirmationEmail>();