I am struggling with how to make all this work in regards to registration.
I can create a single class that implements IConsumer<ISomeMessage>, IConsumer<ISomeOtherMessage>, IConsumer<IThirdMessage>, and IConsumer<ISomeSingleMessage>.
I could also create 4 different consumers....does not matter..less ceremony to have on class for the consumers - especially since they are just wrappers around CQRS.
I can then use your registration overload along with a LoadFrom() and everything will happily use DI and register itself. While this works for some situations, it makes it difficult to split messages across different queues.
We ran across many issues trying to get them registered.
My consumers always have constructor parameters (DI). So that ruled out most ways of registering.
- ep.Consumer(() => new MyMessageLogger(NEED_CONTAINER_RESOLUTION forconstructor););
- ep.Consumer<MyConsumer>(); no parameterless constructor
The only way I figured out how to register them was to create TWO consumers. One consumer per queue that we wanted:
sbc.ReceiveEndpoint(host, "MyQueue", ep =>
{
ConsumerConfiguratorCache.Configure(typeof(MyConsumerOne), ep, c.Resolve<ILifetimeScope>(), "message");
});
sbc.ReceiveEndpoint(host, "AnotherQueue", ep =>
{
ConsumerConfiguratorCache.Configure(typeof(MyConsumerTwo), ep, c.Resolve<ILifetimeScope>(), "message");
});
The above may be equivalent to something like this....still seems very 'consumer centric'
ep.Consumer(new AutofacConsumerFactory<MyConsumerTwo>(c.Resolve<ILifetimeScope>(), "message"));
This seems backwards. Register the concrete class and what it implements will be registered on the endpoint.
Heavily leveraging Autofac DI in our applications, I tend to think of things in terms of registering interfaces and using those interfaces to find a concrete implementation. So, I am thinking about registrations in terms of messages (perhaps incorrectly?).
As such, I would expect to see:
//this would find every IConsumer<> and register each one to the concrete Consumer class it represents.
builder.RegisterConsumers(_assemblies);
builder.Register(c => Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.UseSerilog();
var host = sbc.Host("rabbitmq://localhost"), h =>
{
h.Username("guest");
h.Password("guest");
});
sbc.ReceiveEndpoint(host, "MyQueue", ep =>
{
ep.ListenFor<ISomeMessage>();
ep.ListenFor<ISomeOtherMessage>();
ep.ListenFor<IThirdMessage>();
});
sbc.ReceiveEndpoint(host, "AnotherQueue", ep =>
{
ep.ListenFor<ISomeSingleMessage>();
ep.PrefetchCount = 1;
});
}))
Then when a particular message comes in, MT would query the DI container for who implements IConsumer<ISomeMessage> and use that consumer.
Perhaps the above would take some sort of 'ConsumerFactory' that you called - passing in the messageType and it returns the consumer..
Perhaps AutofacConsumerFactory falls into play here - but it appears to be about a single consumer and supporting a decorator pattern.
Thoughts?