Rebus Windsor容器和内联消息处理程序

时间:2016-12-16 08:56:17

标签: rebus

我正在尝试使用Rebus执行请求/回复,但也使用Windsor容器NuGet包:https://github.com/rebus-org/Rebus.CastleWindsor

查看以下样本后:

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);
        };
    }
}

我知道在使用Windsor容器方法时它应该看起来更像下面,但我不知道如何听取回复:

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 Rebus 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();
    }
}

我面临的问题是我想在我的web api中使用请求/回复模式来请求联系人列表,等待包含检索到的联系人的回复并将其返回给api调用者。

但是如果我想将Windsor容器适配器用于Rebus,IHandlerActivator接口不会公开允许注册内联消息处理程序的.Handle方法,在该方法中,我从回复中抓取联系人,然后将它们发送回api来电。

有没有办法做到这一点,或者我是否错误地解决了这个问题?

编辑:正如您在第一个示例中所看到的,我从Windsor容器中注入IBus接口。 但是,如果我使用注入的总线,我如何告诉它监听从消息处理程序返回的回复?

更新:Rebus.Async正是我所寻找的:https://github.com/rebus-org/Rebus.Async

1 个答案:

答案 0 :(得分: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&#39; .With(...)方法。

当您需要在Windsor中注册处理程序时,您可以利用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>();

在您添加更多信息后更新 - 您说:

  

(...)或我是否错误地接近了这个问题?

我想说&#34;是&#34;,因为服务总线不是很擅长同步请求/回复 - 你应该使用&#34;请求/回复导向&#34;为此,例如HTTP(*)。

另外 - 我对南希几乎一无所知,但我很确定

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

将陷入僵局,至少如果您在ASP.NET中主持Nancy。

你应该总是

await bus.Publish(...);

什么时候可以,在南希,你可以这样做:

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

    await bus.Publish(...);

    (...)
};

PS:最后一件事:只要您希望端点处理消息,请记住保持容器。

在您发布的代码中,您在发布活动后立即处置BuiltinHandlerActivator,这意味着您很可能根本无法处理任何消息。

如果您使用Windsor,当您处理Windsor容器时,将处理公共汽车。

(*)虽然Rebus实际上有Rebus.Async这是一个可以在你的场景中使用的请求/响应API。

我不建议走这条路。如果您打算这样做一次,那么您应该只这样做,然后再也不会这样做:)