Closed matt-psaltis closed 6 years ago
I am foreseeing the need to re-structure the way Rebus is integrated with Autofac because of this.... there was a similar problen with the "Service Provider" container available in ASP.NET Core, where the Rebus configuration ended up being an extension method on the container with a callback.
The callback is then an Action<RebusConfigurer>
which can then be used to continue the usual Rebus configuration spell, e.g. like this:
services.AddRebus(configure => configure
.Logging(l => l.ColoredConsole())
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "Messages"))
.Routing(r => r.TypeBased().MapAssemblyOf<Message1>("Messages")));
I am thinking that the same trick could be applied with Autofac too.
I made an attempt at creating a new API – this test was used to check that it works... its usage could look like this:
// (1)
var builder = new ContainerBuilder();
// set up Rebus configuration callback
builder.AddRebus(configure => configure
.Logging(l => l.Console(minLevel: LogLevel.Debug))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")));
// build the container instance
var container = builder.Build();
// start the bus when you feel like it
container.UseRebus();
// remember to dispose the container to stop the bus
container.Dispose();
Looking at this now, I wonder why I followed the naming from Microsoft's ServiceProvider (Add***
followed by Use***
) – I think it would be better if the naming was more idiomatic considering the selected container, e.g. more like this with Autofac:
// (2)
var builder = new ContainerBuilder();
// set up Rebus configuration callback
builder.RegisterRebus(configure => configure
.Logging(l => l.Console(minLevel: LogLevel.Debug))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")));
// build the container instance
var container = builder.Build();
// start the bus when you feel like it
container.StartBus();
// remember to dispose the container to stop the bus
container.Dispose();
Since Autofac provides a callback, which gets invoked when the container is built, the bus could easily be started automatically on builder.Build()
– wouldn't that actually be preferable?
If that was done, the code could be reduced to this:
// (3)
var builder = new ContainerBuilder();
// set up Rebus configuration callback
builder.RegisterRebus(configure => configure
.Logging(l => l.Console(minLevel: LogLevel.Debug))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")));
// build the container instance and start the bus
var container = builder.Build();
// remember to dispose the container to stop the bus
container.Dispose();
I think I prefer option (3)
– what do you think?
Definitely like the simplicity of option 3. Is the auto start of the container (edit: I mean bus!) using Autofac's AutoActivate feature? If so, the auto start of the container can be controlled via the builder.Build
overload. I have some integration tests that selectively disable certain containers so having a way to do that is useful for my use case. That's the only question I have really, its tidy and simple - Nice work!
I think this makes sense too... this usage pattern isnt in the latest rebus.autofac, correct?
I haven't got around to finishing it up yet, but I think it's actually only a matter of fixing the tests
turns out I had a couple of hours this evening 😁
5.0.0-b01 is out in a few minutes with the new syntax:
var builder = new ContainerBuilder();
builder.RegisterRebus(configure => configure
.Logging(l => l.Console(minLevel: LogLevel.Debug))
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")));
var container = builder.Build();
// program is running now
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
// always dispose container when program shuts down
container.Dispose();
I would be happy if someone well-versed in The Ways Of Autofac would try it out, and then I'll release 5.0.0 when someone says it's good
Very nice! Thanks @mookid8000. Not sure I've read 'The Ways Of Autofac' scroll yet, but I'll give the changes a try anyways! Thanks again
I just updated, and confirmed this is good to go.
unless someone objects within the next 30 s I will release 5.0.0 of Rebus.Autofac
.....
too late, it's out now 😄
A little late to the game but updated my nuget packages and got a new Rebus Autofac. Is there a new way to register the handlers ?
This was how I did it before: //_builder.RegisterAssemblyTypes(typeof(HeartBeatCommandHandler).Assembly) // .Where(x => typeof(IHandleMessages).IsAssignableFrom(x)) // .AsClosedTypesOf(typeof(IHandleMessages<>)) // .AsImplementedInterfaces() // .InstancePerDependency() // .PropertiesAutowired();
But now I'm getting ...could not be dispatched to any handlers.
Oh, I didn't realize that the old package provided these extensions.
You should register your handlers as implementations of IHandleMessages<>
, closing it with whichever message they handle – e.g. you would register HeartBeatCommandHandler
as an implementation of IHandleMessages<HeartBeatCommand>
I am not an expert on Autofac, so I don't know if special configuration is required in order to have it resolved when the activator tries to resolve an IEnumerable<IHandleMessages<HeartBeatCommand>>
(because that's what happens underneath the covers).
Do I have to register each handler separate? That is a little backwards. This have always worked but after the upgrade to Rebus 4.1 and the newest Rebus.Autofac it went south :-(
It could also be that I've forgot something or dones something wrong in the new way to register Rebus this is my code:
`` private ContainerBuilder _builder; private void RegisterBus() { string queueAddress = Constants.SignatureQueueAddress; int numberOfWorkes = _appSettingsReader.NumberOfWorkers > 0 ? _appSettingsReader.NumberOfWorkers : 10; int maxParallelismFactor = 3;
queueAddress = queueAddress.ToDebugQueueAddress();
numberOfWorkes = 1;
maxParallelismFactor = 1;
if (_appSettingsReader.BetaSite)
queueAddress += "-beta";
var errorQueueAddress = $"{queueAddress}-error";
_builder.RegisterAssemblyTypes(typeof(HeartBeatCommandHandler).Assembly)
.Where(x => typeof(IHandleMessages).IsAssignableFrom(x))
.AsClosedTypesOf(typeof(IHandleMessages<>))
.AsImplementedInterfaces()
.InstancePerDependency()
.PropertiesAutowired();
var cosmosSettings = _appSettingsReader.CosmosSettings;
_builder.RegisterRebus(configure =>
configure
.Transport(t => t.UseAzureServiceBus(_appSettingsReader.ServicebusConnectionString, queueAddress))
.Sagas(
s =>
s.StoreInCosmosDb(new DocumentClient(new Uri(cosmosSettings.CollectionUrl), cosmosSettings.AuthKey, new ConnectionPolicy() { EnableEndpointDiscovery = false }),
_appSettingsReader.CosmosSettings.DataBaseId,
_appSettingsReader.CosmosSettings.CollectionId, true)
)
.Routing(r => r.TypeBased().MapAssemblyOf<HeartBeatCommand>(queueAddress))
.Logging(l => l.Serilog())
.Options(o =>
{
o.SimpleRetryStrategy(secondLevelRetriesEnabled: true, maxDeliveryAttempts: 5,errorQueueAddress: errorQueueAddress);
o.EnableAutoScaling(numberOfWorkes, (numberOfWorkes * maxParallelismFactor));
o.EnableCompression( );
o.EnableEncryption(_appSettingsReader.RebusEncryption);
}));
}
``
@mookid8000 It looks the problem was sometinh else the Routing in Rebus does not take all messages in an assembly longer. Have two folders (and to subnamespaces) and then I have to map both like this:
.Routing(r => r.TypeBased().MapAssemblyOf
Earlier the first mapping was sufficient.
The Autofac team are currently discussing alternatives to the use of ContainerBuilder.Update and this package will become incompatible at some stage in the future if the removal of the deprecated methods goes ahead.
The discussion can be found here: https://github.com/autofac/Autofac/issues/811