NServiceBus Удаление IBus - Использование IPipelineContext и IMessageSession

Я нахожусь в процессе миграции NServiceBus до v6 и нахожусь на контрольно-пропускном пункте в процессе удаления ссылки на IBus.

Мы опираемся на общую библиотеку для многих наших приложений (веб-сайт, микро-сервисы и т. Д.), И эта библиотека имеет концепцию IEventPublisher, которая по сути является интерфейсом отправки и публикации. Эта библиотека не имеет знаний о NSB. Затем мы можем предоставить реализацию этого IEventPublisher, используя DI из приложения, это позволяет очень легко заменить передачу сообщений библиотеки другой технологией.

Итак, в результате мы получаем реализацию, аналогичную

public class NsbEventPublisher : IEventPublisher
{
    IEndpointInstance _instance;

    public NsbEventPublisher(IEndpointInstance endpoint)
    {
        instance = endpoint;
    }

    public void Send(object message)
    {
        instance.Send(message, sendOptions);
    }

    public void Publish(object message)
    {
        instance.Publish(message, sendOptions);
    }
}

Это упрощение того, что на самом деле происходит, но иллюстрирует мою проблему. Теперь, когда у контейнера DI запрашивается IEventPublisher, он знает, что должен вернуть NsbEventPublisher, и он знает, как разрешить IEndpointInstance, поскольку мы связываем это в загрузчике для веб-сайта с контейнером как синглтон. Все хорошо, и мой сайт работает отлично.

Сейчас я выполняю миграцию микросервисов (работающих в NSB.Host), и контейнер DI отказывается разрешать IEndpointInstance при разрешении зависимостей в обработчике сообщений. Чтение документов это намеренно, и я должен использовать IMessageHandlerContext в обработчике сообщений. https://docs.particular.net/nservicebus/upgrades/5to6/moving-away-from-ibus Документы даже избегают проблемы, с которой я столкнулся в нижнем примере вокруг класса MyContextAccessingDependency. Предлагается пропустить контекст сообщения через метод, который устанавливает жесткую зависимость от кода, выполняемого в контексте обработчика сообщений.

Я хотел бы иметь доступ к отправителю / издателю, и контейнер DI может дать мне правильную реализацию. Код не нуждается в какой-либо концепции вызывающего, и если он был вызван из обработчика сообщений или из собственного приложения, которое просто хочет опубликовать.

Я вижу, что есть два интерфейса для связи с "Bus" IPipelineContext и IMessageSession, которые расширяют интерфейсы IMessageHandlerContext и IEndpointInstance соответственно. Что меня интересует, так это некоторое объединение двух интерфейсов, которые связываются NSB в контейнер, чтобы я мог принять интерфейс, который отправляет / публикует сообщения. В обработчике это IMessageHandlerContext, а в моем собственном размещенном приложении - IEndPointInstance.

Сейчас я хочу изменить свою реализацию IEventPublisher в зависимости от хостинга приложений. Я просто надеялся, что возможно будет некоторое обсуждение того, как этот подход моделируется без надежного интерфейса для отправки / публикации, независимо от того, что инициировало выполнение пути кода.

1 ответ

Несколько вещей, чтобы отметить, прежде чем я доберусь до кода:

  • Абстракция над абстракцией обещает, никогда не работает. Я никогда не видел аргумента "Я собираюсь абстрагироваться от ESB/Messaging/Database/ORM, чтобы я мог поменять его в будущем". Когда-либо.

  • Когда вы абстрагируете такую ​​функцию отправки сообщений, вы потеряете некоторые функции, которые предоставляет библиотека. В этом случае вы не можете выполнять "Беседы" или использовать "Саги", которые могут помешать вашему общему опыту, например, при использовании инструментов мониторинга и просмотра диаграмм в ServiceInsight вы не увидите всю картинку, а только нюансы сообщений, проходящих через система.

Теперь, чтобы это работало, вам нужно зарегистрироваться IEndpointInstance в вашем контейнере, когда ваша конечная точка запускается. Затем этот интерфейс может использоваться в вашей инъекции зависимости, например, в NsbEventPublisher отправлять сообщения.

Примерно так (в зависимости от того, какой контейнер IoC вы используете, здесь я предполагаю, что Autofac):

static async Task AsyncMain()
{
    IEndpointInstance endpoint = null;

    var builder = new ContainerBuilder();

    builder.Register(x => endpoint)
           .As<IEndpointInstance>()
           .SingleInstance();   

    //Endpoint configuration goes here...

    endpoint = await Endpoint.Start(busConfiguration)
                             .ConfigureAwait(false);
}

Проблемы с использованием IEndpointInstance / IMessageSession упомянуты здесь.

Другие вопросы по тегам