Manipulate Pipeline with Behaviors

Component: NServiceBus
NuGet NServiceBus (4.x)
Standard support for version 4.x of NServiceBus has expired. For more information see our Support Policy.

Pipelines are made up of a group of steps acting on the same level of abstraction. This allows scenarios such as

  • Defining a step that works with the "incoming physical" message before it has been deserialized.
  • Defining a step that is executed before and after each handler invocation (remember: there can be multiple message handlers per message).

Extending the pipeline is done with a custom behavior implementing Behavior<TContext>.TContext is the context of the stage that the behavior belongs to.

4.5 NServiceBus
public class SampleBehavior :
    IBehavior<HandlerInvocationContext>
{
    public void Invoke(HandlerInvocationContext context, Action next)
    {
        // custom logic before calling the next step in the pipeline.

        next();

        // custom logic after all inner steps in the pipeline completed.
    }
}

In the above code snippet the SampleBehavior class derives from the Behavior contract and targets the incoming context. This tells the framework to execute this behavior after the incoming raw message has been deserialized and a matching message type has been found. At runtime, the pipeline will call the Invoke method of each registered behavior passing in as arguments the current message context and an action to invoke the next behavior in the pipeline.

Each behavior is responsible to call the next step in the pipeline chain by invoking next().

Add a new step

To add a custom behavior to the pipeline define a step for it:

4.5 NServiceBus
class NewStepInPipeline :
    PipelineOverride
{
    public override void Override(BehaviorList<HandlerInvocationContext> behaviorList)
    {
        behaviorList.InsertAfter<InvokeHandlersBehavior, SampleBehavior>();
    }

    // Classes inheriting from PipelineOverride are registered by convention.
    // No need to explicitly register.
}

Replace an existing step

To replace the implementation of an existing step replace it with a custom behavior:

4.5 NServiceBus
class ReplaceExistingBehavior :
    PipelineOverride
{
    public override void Override(BehaviorList<HandlerInvocationContext> behaviorList)
    {
        behaviorList.Replace<InvokeHandlersBehavior, MyInvokeHandlersBehavior>();
    }

    // Classes inheriting from PipelineOverride are registered by convention.
    // No need to explicitly register.
}
Steps can also be registered from a Feature.

Exception Handling

Exceptions thrown from a behavior's Invoke method bubble up the chain. If the exception is not handled by a behavior, the message is considered as faulted which results in putting the message back in the queue (and rolling back the transaction) or moving it to the error queue (depending on the endpoint configuration).

Mutators versus Behavior

Shared concepts and functionality

  • Can manipulate pipeline state
  • Can be executed in the incoming or outgoing pipeline
  • Exceptions cause bubble up the pipeline and are handled by the Recoverability

Differences

Note that these are relative differences. So, for example, a Behavior is only "high complexity" in comparison to a Mutator.

MutatorBehavior
Complexity to implementLowHigh
FlexibilityLowHigh
Location in pipelineFixedFlexible
Complexity to testLowMedium*
Can control nested actionNoYes
Effects call stack depthNoYes
Can replace existing BehaviorNoYes

Related Articles


Last modified