2016-12-16 2 views
1

Я пытаюсь выполнить запрос/ответ с Ребус, но и с помощью Windsor контейнера NuGet пакет: https://github.com/rebus-org/Rebus.CastleWindsorРебус Windsor контейнеров и inlinemessage обработчики

Посмотрев на следующих образцах:

https://github.com/rebus-org/RebusSamples/tree/master/RequestReply

https://github.com/rebus-org/RebusSamples/tree/master/Integration

Я собрал этот пример ниже вместе:

public class ContactModule : NancyModule 
{ 
    public ContactModule(IBus bus) 
    { 
     Get["/v1/contact"] = parameters => 
     { 
      var contacts = new List<Contact>(); 

      using (var activator = new BuiltinHandlerActivator()) 
      { 
       var settings = new Settings(); 

       activator.Handle<GetContactsResponse>(response => 
       { 
        contacts = response.Contacts; 

        return Task.FromResult(0); 
       }); 

       Configure.With(activator) 
        .Logging(l => l.ColoredConsole(LogLevel.Warn)) 
        .Transport(t => t.UseRabbitMq(
         settings.RabbitMQConnectionString, 
         settings.OutputQueueName)) // we listen for messages in the output queue 
        .Routing(r => r.TypeBased().MapAssemblyOf<GetContactsRequest>(settings.InputQueueName)) // but we publish to the input queue 
        .Options(o => 
        { 
         o.EnableCompression(); 
         o.EnableEncryption(settings.MessageEncryptionKey); 
        }) 
        .Start(); 

       activator.Bus.Publish(new GetContactsRequest``()).Wait(); 
      } 

      return Response.AsJson(contacts); 
     }; 
    } 
} 

Я знаю, что при использовании контейнера подхода Виндзорского он должен выглядеть примерно ниже, но я не знаю, как слушать ответ:

public class ContactModule : NancyModule 
{ 
    public ContactModule(IBus bus) 
    { 
     Get["/v1/contact"] = parameters => 
     { 
      var contacts = new List<Contact>(); 

      bus.Publish(new GetContactsRequest()).Wait(); 

      // How do I listen for the reply? 

      return Response.AsJson(contacts); 
     }; 
    } 
} 

Моего обработчик сообщений:

public class GetContactsHandler : IHandleMessages<GetContactsRequest> 
{ 
    private readonly IBus _bus; 
    private readonly Settings _settings; 

    public GetContactsHandler(IBus bus, Settings settings) 
    { 
     _bus = bus; 
     _settings = settings; 
    } 

    public async Task Handle(GetContactsRequest request) 
    { 
     // Fetch contacts from db... 
     var contacts = new List<Contact>(); 
     await _bus.Reply(new GetContactsResponse {Contacts = contacts}); 
    } 
} 

My Ребус Windsor инсталлятор:

public class RebusInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     var settings = new Settings(); 

     Configure.With(new CastleWindsorContainerAdapter(container)) 
      .Logging(l => l.ColoredConsole(LogLevel.Warn)) 
      .Transport(t => t.UseRabbitMqAsOneWayClient(
       settings.RabbitMQConnectionString)) 
      .Routing(r => r.TypeBased().MapAssemblyOf<GetContactsRequest>(settings.InputQueueName)) 
      .Options(o => 
      { 
       o.EnableCompression(); 
       o.EnableEncryption(settings.MessageEncryptionKey); 
      }) 
      .Start(); 
    } 
} 

проблема я столкнулся в том, что я хочу, чтобы нас e шаблон запроса/ответа в моем веб-приложении api, чтобы запросить список контактов, дождитесь ответа, содержащего извлеченные контакты, и верните их вызывающему абоненту.

Но если я хочу использовать адаптер контейнера Windsor для интерфейса Rebus, интерфейс IHandlerActivator не предоставляет метод .Handle, который позволяет регистрировать встроенные обработчики сообщений, в которых я захватываю контакты из ответа, а затем отправляю их обратно абонент api.

Есть ли способ сделать это, или я неправильно подхожу к проблеме?

Редактировать: Как вы можете видеть в первом примере, я впрыскиваю в интерфейс IBus из контейнера Windsor. Но если я использую инъецированную шину, как я могу сказать, что она отвечает за ответ, возвращенный из обработчика сообщений?

Update: Rebus.Async было именно то, что я искал: https://github.com/rebus-org/Rebus.Async

ответ

2

Когда вы используете реальный контейнер IoC, вы должны создать класс, который реализует IHandleMessages<TMessage>, например, например:

public class GetContactsRequestHandler : IHandleMessages<GetContactsRequest> 
{ 
    readonly IBus _bus; 

    public GetContactsRequestHandler(IBus bus) 
    { 
     _bus = bus; 
    } 

    public async Task Handle(GetContactsRequest request) 
    { 
     var reply = new GetContactsReply(...); 

     await _bus.Reply(reply); 
    } 
} 

, который масштабируется намного лучше, когда вы добавляете обработчики и помогаете приложениям и услугам домена в вашей программе.

Это, конечно, означает, что вы должны принести пакет Rebus.CastleWindsor NuGet и передать WindsorContainerAdapter методу Rebus '.With(...).

Если вам необходимо зарегистрировать обработчик в Виндзоре, вы можете воспользоваться методами расширения от Rebus.CastleWindsor, который позволяет делать эти вещи:

// register all handler types from this assembly 
windsorContainer.AutoRegisterHandlersFromThisAssembly(); 

// register all handler types from typeof(SomeHandler).Assembly 
windsorContainer.AutoRegisterHandlersFromAssemblyOf<SomeHandler>(); 

// register one particular type as a message handler 
windsorContainer.RegisterHandler<GetContactsRequestHandler>(); 

UPDATE после добавления еще некоторой информации - Вы сказали:

(...) или я неправильно подхожу к проблеме?

, и я бы сказал «да», потому что служебная шина не очень хороша при синхронном запросе/ответе - вы должны использовать что-то «запрос/ответ-ориентированный» для этого, например. HTTP (*).

Кроме того - я почти ничего не знает о Нэнси, но я уверен, что

bus.Publish(...).Wait(); 

будет тупик, по крайней мере, если вы хостинг Нэнси в ASP.NET.

Вы должны всегда

await bus.Publish(...); 

, когда вы можете, и в Нанси, вы можете просто сделать это:

Get["/v1/contact"] = async (parameters, ct) => 
{ 
    (...) 

    await bus.Publish(...); 

    (...) 
}; 

PS: Последняя вещь: Помните, чтобы держать контейнер вокруг до тех пор, так как вы хотите, чтобы ваша конечная точка обрабатывала сообщения.

В опубликованном вами коде вы размещаете BuiltinHandlerActivator сразу после публикации события, а это значит, что вы, скорее всего, не обработаете никаких сообщений вообще.

Если вы используете Windsor, шина будет утилизирована, когда вы разместите контейнер Windsor.


(*) Хотя Ребус на самом деле есть Rebus.Async, который является запрос/ответ API, которые могут быть использованы в вашем сценарии.

Я бы не рекомендовал идти по этой дороге. Вероятно, вы должны это сделать только в том случае, если вы намереваетесь сделать это один раз, а затем никогда больше не будете :)

+0

Прежде всего, я хочу поблагодарить вас за такой быстрый краткий ответ. Я очень ценю ваше время и усилия. Вы бы сказали, что лучше использовать Rebus для передачи работы, например создания ресурса и выполнения асинхронной работы, а затем использовать HTTP для извлечения ресурсов? Кажется, стыдно смешивать методы общения, мне понравилась идея использования шины для всех внутренних сообщений в моем стеке. – Jam

+0

Да - Rebus (и этот тип библиотеки сообщений в целом) предназначен для асинхронной обработки вещей надежным способом, что часто делает их медленнее, чем запрос HTTP. – mookid8000

+0

Следовательно, вы должны использовать шину, когда хотите убедиться, что информация, полученная в вашем сообщении, обработана, и вы хотите, чтобы обработка была повторена в случае ошибок. – mookid8000

 Смежные вопросы

  • Нет связанных вопросов^_^