Getting Started

Upgrade NServiceBus pipeline extensions from Version 7 to 8

Component: NServiceBus

This documentation provides information on breaking changes affecting maintainers of pipeline extensions such as pipeline behaviors and message mutators.


IManageUnitOfWork interface is no longer recommended. The unit of work pattern is more straightforward to implement in a pipeline behavior, where the using keyword and try/catch blocks can be used.

Custom unit of work sample is an example of the recommended approach.

Message mutators with Dependancy Injection (DI)

Message mutators that operate on serialized messages (IMutateIncomingTransportMessages and IMutateOutgoingTransportMessages) in NServiceBus version 8 represent the message payload as ReadOnlyMemory<byte> instead of byte[]. As a result, the messages are immutable and it is no longer possible to change their content. Instead, a modified copy of the payload must be provided and assigned to the Body property of the context.

In NServiceBus version 7 and below message mutators could be registered in two ways: using a dedicated endpointConfiguration.RegisterMessageMutator API or via a dependency injection container. In version 8 only the dedicated API is supported. Mutators registered in the container are ignored.

Removing a behavior from the pipeline is obsolete

The Remove method is no longer available in PipelineSettings. In order to disable a behavior, replace the behavior with an empty one.

Pipeline delivery constraints

The TryGetDeliveryConstraint method on the NServiceBus.Extensibility.ContextBag property has been removed. In order to access delivery constraints from within the pipeline, use NServiceBus.Extensibility.ContextBag.TryGet instead.

var extensions = context.Extensions;
if (extensions.TryGet(out DiscardIfNotReceivedBefore constraint))
    timeToBeReceived = constraint.MaxTime;

Pipeline context types changes

Throughout the pipeline, all context types (e.g. context for behaviors, stage connectors, and message mutators) have been updated to use ReadOnlyMemory<byte> instead of byte[]. These are:

  • MutateIncomingTransportMessageContext
  • MutateOutgoingTransportMessageContext
  • ConnectorContextExtensions
  • IIncomingPhysicalMessageContext
  • IncomingPhysicalMessageContext
  • IOutgoingPhysicalMessageContext
  • OutgoingPhysicalMessageContext
  • SerializeMessageConnector

Message body reference valid only in scope of message processing

References to message bodies exposed through context types as ReadOnlyMemory<byte> are valid only for the time of message processing. After the processing finishes, the data may not be assumed valid.

If message body value is required after processing finishes it must be copied it while it is still in scope.

Message Mutators: Updating of message bodies

The message mutator API for changing the message body has changed. Instead, of UpdateMessage(byte[] body) method MutateIncomingTransportMessageContext and MutateOutgoingTransportMessageContext expose Body property of type ReadOnlyMemory<byte>.

In scenarios, where mutators replace the whole message body switching to pipeline behavior might bring significant performance benefits. With a pipeline behavior it is possible to reduce allocations via ArrayPool<byte> or packages like RecyclableMemoryStream.

Last modified