Setting up a Mutator with Scoped Dependencies

Hi,

TLDR; How can I properly create a mutator that has dependencies?

I am building a solution that serialized a bag of data that is initialised by an API Middleware pipeline this data is currently registered as per LifetimeScope in, Autofac terms, I am able to resolve this dependency on the controller, but later on when I try to resolve this dependency within a mutator that should serialize the bag of data into a header, it is no longer available.

I have tried registering the Mutator with InstancePerCall and InstancePerUnitOfWork but neither gives me the object in the same state as on the controller. Does the sending pipeline create a new scope?

I have created the mutator implementing IMutateOutgoingTransportMessages and registered it through RegisterComponents(components => components.Configure<Mutator>(DependencyLifecycle.InstancePerCall)) on the EndpointConfiguration.

I’ve placed a breakpoint in the MutateOutgoing method and the constructor but I never hit the constructor, not sure why this is, but more importantly, the constructor injected dependency is no longer the initialised bag of data.

Thanks in advanced!

1 Like

Hi Riaan

What Version of NServiceBus are you using? Are you sending messages as part of an incoming message or as part of a message session?

We are building all the mutators every time the outgoing logical context phase is invoked (exception the ones that are registered via Message Mutators • NServiceBus • Particular Docs)

So registering as InstancePerCall should work. You can verify that by changing

endpointConfiguration.RegisterMessageMutator(new ValidationMessageMutator());
endpointConfiguration.RegisterMessageMutator(new TransportMessageCompressionMutator());

to

        endpointConfiguration.RegisterComponents(c => c.ConfigureComponent<ValidationMessageMutator>(DependencyLifecycle.InstancePerCall));
        endpointConfiguration.RegisterComponents(c => c.ConfigureComponent<TransportMessageCompressionMutator>(DependencyLifecycle.InstancePerCall));

in Message Mutators • NServiceBus Samples • Particular Docs

Regards
Daniel

Hi Daniel.

NServiceBus version 7.2.0 so I believe it is the latest.

Sending via a Message session, and indeed I only use the RegisterComponents extension on the EndpointConfiguration, also to add this is a mutator on the OutgoingTransportMessage. Is there a moment on the outgoing messaging pipeline were a new Scope is created.

Regards
Riaan

Hi Riaan

With the message session there is no scope. So that means if you register your bag at the moment when the mutator is invoked whatever registration is there will be taken. So in your case because we don’t have a scope it probably makes sense to have a helper class with an AsyncLocal that you register as a singleton on the container or directly use in the mutator.

Something like

static class FloatingHeaders {
   public static AsyncLocal<Dictionary<string, string>> Headers = new AsyncLocal<...>;
}

and then before the session send you set the async local value

FloatingHeaders.Headers.Value = new Dictionary<string, string>();

if you register this class as a singleton in the container then the property doesn’t have to be static but other than that it would behave equally to the static version.

Does that help?

Regards
Daniel