rebus-org / rebus.autofac Goto Github PK
View Code? Open in Web Editor NEW:bus: Autofac container adapter for Rebus
Home Page: https://mookid.dk/category/rebus
License: Other
:bus: Autofac container adapter for Rebus
Home Page: https://mookid.dk/category/rebus
License: Other
When GetHandlerInvokers in ActivateHandlersStep for a failed message (FailedMessageWrapper), no invokers can be found, resulting in an empy list of handlers.
Register in Rebus.Autofac:
autofacBus.Subscribe<string>().Wait();
autofacBus.Subscribe<IFailed<string>>().Wait();
--> Do not work!
Register with BuildInActivator:
rebusActivator.Bus.Subscribe<string>();
rebusActivator.Bus.Subscribe<IFailed<string>>();
-- Working OK!
If you are not starting the bus, the process to start it is different now in v8. We should update the docs.
Hello guys,
One of the common scenario for ASP .NET Core application is registering all dependencies in ConfigureServices
method and applying DB migrations in Configure
method in Startup
class.
In case of using SQL based transport for messages, database may not exist on the moment of container build up. Why Rebus.Autofac
decides when to start up the bus?
Hi! I noticed that ComponentContext
cannot be resolved in steps like in Rebus.ServiceProvider
package where the ServiceProviderProviderStep
provides the ServiceProvider
for the rest of the pipeline. Would it be possible to enable resolving ComponentContext
in steps for the next version?
For example in my project we are using rebus middleware to fetch the headers from http context and set them to message context for audit purposes. Something like this:
`/// <summary>
/// Implementation of <see cref="IOutgoingStep"/> that fetches the requestId neccesseary for audit trail
/// from Http Context and attaches it to rebus message context.
/// </summary>
internal class AttachRequestIdToOutgoingMessagesStep : IOutgoingStep
{
public async Task Process(OutgoingStepContext context, Func<Task> next)
{
var componentContext = context.Load<IComponentContext>();
var httpContextAccessor = componentContext.Resolve<IHttpContextAccessor>();
var requestId = httpContextAccessor.HttpContext.Request.Headers["x-request-id"];
if (!string.IsNullOrWhiteSpace(requestId))
{
var message = context.Load<Message>();
message.Headers["x-request-id"] = requestId.ToString();
}
await next();
}
}`
But in order for our steps to be able to resolve services from ComponentContext
, I created an extension method which will enable the ComponentContextProviderStep
to provide the ComponentContext
for the rest of the pipeline. Like this:
`[StepDocumentation("Adds the component context to the incoming/outgoing step context, thus making it available for the rest of the pipeline.")]
public class ComponentContextProviderStep : IIncomingStep, IOutgoingStep
{
readonly IComponentContext _context;
/// <summary>
/// Creates the step
/// </summary>
public ComponentContextProviderStep(IComponentContext context) =>
_context = context ?? throw new ArgumentNullException(nameof(context));
/// <summary>
/// Saves the component context in the pipeline's context and invokes the rest of the pipeline
/// </summary>
public async Task Process(IncomingStepContext context, Func<Task> next)
{
context.Save(_context);
await next();
}
/// <summary>
/// Saves the component context in the pipeline's context and invokes the rest of the pipeline
/// </summary>
public async Task Process(OutgoingStepContext context, Func<Task> next)
{
context.Save(_context);
await next();
}
}`
Also I played around a bit with the Rebus.Autofac
package and managed to set up the ComponentContextProviderStep
.
Like this:
`public static void RegisterRebus(this ContainerBuilder containerBuilder, Func<RebusConfigurer, IComponentContext, RebusConfigurer> configure)
{
if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));
if (configure == null) throw new ArgumentNullException(nameof(configure));
new AutofacHandlerActivator(containerBuilder, (configurer, context) => configure(
configurer.Options(o => o.Decorate<IPipeline>(c =>
{
var pipeline = c.Get<IPipeline>();
var step = new ComponentContextProviderStep(context.Resolve<IComponentContext>());
return new PipelineStepConcatenator(pipeline)
.OnReceive(step, PipelineAbsolutePosition.Front)
.OnSend(step, PipelineAbsolutePosition.Front);
}))
, context), startBus: true, enablePolymorphicDispatch: false);
}`
I tested this and it works fine (I was able to resolve HttpContextAccessor
in my test step) but I'm not sure if this is the right implementation.
I am not sure if there is an issue per-se, but I am investigating an issue we are seeing sometimes where a message handler is being executed after the root container has been disposed, throwing ObjectDisposedException
's.
In my digging I fell upon this interesting issue over on the Rebus main repository: rebus-org/Rebus#976
It sounds very similar and from the looks of it, it was resolved by the RebusBackgroundService
here: https://github.com/rebus-org/Rebus.ServiceProvider/blob/master/Rebus.ServiceProvider/ServiceProvider/Internals/RebusBackgroundService.cs
The thing is, we are using Autofac as out IoC layer, on top of ServiceProvider
/ IServiceCollection
. And from the looks of it, I cannot find any similar code in this repository handling the graceful shutdown when the root container is disposed.
Might there be a similar edge case here?
It occurs rather seldom, but often enough to be a source of noise in our logs ๐
Thanks for the changes allowing access to IComponentContext.
I must say though, I do prefer the existing approach. This allowed for exposing RebusConfigurer separately before the bus was created.
This allowed for the container to create the RebusConfigurer instance with all the default options and properties etc, but allowed for the Routing to be configured before creating the bus.
Since there's no option (as far as i know?) to mess with routing after the bus is created, this results in a lot of boilerplate code to configure the bus instead of creating it with the majority of options by IoC.
Am I missing some sort of option to configure routing after the bus is created?
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.
With the old API, we could access IComponentContext to resolve components used in the Rebus configuration - e.g. IDocumentStore if using the RavenDB connectors.
e.g.
var busConfiguration = Rebus.Config.Configure.With(new AutofacContainerAdapter(c.Resolve<IContainer>()))
.Logging(l => l.Serilog(Log.Logger))
.Timeouts(t => t.StoreInRavenDb(c.Resolve<IDocumentStore>()))
.Sagas(s => s.StoreInRavenDb(c.Resolve<IDocumentStore>()))
.Transport(t => t.UseRabbitMq(connectionString, inputQueueName))
How can we access the ComponentContext with this new API to allow for resolving components for the transport registrations etc?
Cheers.
Hi, thanks for implementing Rebus and all it's goodies!
I am using RegisterHandlersFromAssemblyOf to register my handlers.
However, based on my understanding, even though I use it, I still need to subscribe to particular messages.
The scenario I have
I want to register all handlers( let's say I have 3 handlers ) in an assembly and based on a config value, I want to subscribe only to some messages (not all). So, I call RegisterHandlersFromAssemblyOf, I build the container, I subscribe to only 1 message type but when I run the application, my app handles all 3 types of messages.
If I use builder.RegisterHandler and register only the handler I need, it then handles only that type of message after I subscribe to it.
Is it a bug or I missunderstood how to use RegisterHandlersFromAssemblyOf + Subscribe?
Thank you!
Is there a reason why only one bus is allowed per autofac container? On our project we would like to register 2 buses through keyed injection, each with a different transport. Is that possible?
Thanks
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: autofac/Autofac#811
Hi,
Could you change line 50 in https://github.com/rebus-org/Rebus.Autofac/blob/master/Rebus.Autofac/Rebus.Autofac.csproj to use the correct casing.
If you are using .NET Core with project.json files this causes an issue that rebus cannot be found (since it should be Rebus)
Before:
<ItemGroup>
<PackageReference Include="rebus" Version="4.0.0-b05" />
<PackageReference Include="Autofac" Version="4.4.0" />
</ItemGroup>
After:
<ItemGroup>
<PackageReference Include="Rebus" Version="4.0.0-b05" />
<PackageReference Include="Autofac" Version="4.4.0" />
</ItemGroup>
Thanks
While using Autofac container, is it possible to get the rebusConfigurer instance as we get with BuiltInActivator?
Activator = new BuiltinHandlerActivator();
RebusConfigurer rebusConfigurer = Configure.With(Activator);
I use the lib with rabbitMq. Config is something like
builder.RegisterRebus((configurer, context) => configurer
.Logging(l => l.Serilog())
.Transport(t => t.UseRabbitMq("amqp://docker", "testappqueue"))
.Options(o => {
o.SetNumberOfWorkers(1);
o.SetMaxParallelism(30);
}));
If a message was received by rabbitMq while the application was not running it tries to process the message before initialization finished. The reason is _container is null in the code below
ILifetimeScope CreateLifetimeScope()
{
var scope = _container.BeginLifetimeScope();
transactionContext.OnDisposed(() => scope.Dispose());
return scope;
}
Hello!
There is a problem with the current implementation of AutofacHandlerActivator. In case an application uses ContravariantRegistrationSource the handlers will be duplicated due to this code:
var typesToResolve = messageType.GetBaseTypes()
.Concat(new[] {messageType})
ContravariantRegistrationSource already returns handlers for base types automatically, so you just add them one more time.
The possible solution is to add Distinct before returning the list of handlers:
return types.SelectMany(type => (IEnumerable<IHandleMessages>) lifetimeScope.Resolve(type)).Distinct();
This line should not include the message type itself, since line below already does. GetBaseTypes(includeSelf: false)
should fix this issue.
I tried to upgrade to the latest packaged and it fails:
Perhaps the solution is to mark this project itself as also not being CLS compliant?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.