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 упомянуты здесь.