Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Header propagation using the pipeline

Component: NServiceBus
NuGet Package: NServiceBus (8.x)

Introduction

This sample shows how to use the NServiceBus pipeline to copy a header from an incoming message to an outgoing message. This allows information to propagate along a message conversation transparently.

Code walk-through

Creating the behavior

The behavior will check for an incoming message with the CustomerId header. If one is found, the header value is copied to the outgoing message:

class PropagateCustomerIdHeaderBehavior : Behavior<IOutgoingLogicalMessageContext>
{
    public override Task Invoke(IOutgoingLogicalMessageContext context, Func<Task> next)
    {
        if (context.TryGetIncomingPhysicalMessage(out var incomingMessage))
        {
            if (incomingMessage.Headers.TryGetValue("CustomerId", out var incomingConversationId))
            {
                context.Headers["CustomerId"] = incomingConversationId;
            }
        }

        return next();
    }
}

Registering the behavior

The following code registers the behavior in the receive pipeline:

endpointConfiguration.Pipeline.Register(
    new PropagateCustomerIdHeaderBehavior(),
    "Copies CustomerId header from incoming to outgoing messages"
);

Sending a message

The sender sets a custom CustomerId header on the message before sending it:

var customerId = Guid.NewGuid().ToString();
var sendOptions = new SendOptions();
sendOptions.SetHeader("CustomerId", customerId);

await endpoint.Send(new ProcessOrder(), sendOptions);
Console.WriteLine($"Message sent, customerId = {customerId}.");

Message handlers

The message handlers can access the custom CustomerId header:

public Task Handle(ProcessOrder message, IMessageHandlerContext context)
{
    context.MessageHeaders.TryGetValue("CustomerId", out var customerId);
    Console.WriteLine($"Recieved ProcessOrder for customer {customerId}. Shipping");

    return context.SendLocal(new ShipOrder());
}

public Task Handle(ShipOrder message, IMessageHandlerContext context)
{
    context.MessageHeaders.TryGetValue("CustomerId", out var customerId);
    Console.WriteLine($"Shipping Order for customer {customerId}.");

    return Task.CompletedTask;
}

Note that the second handler is for a message that did not have the CustomerId header explicitly set. It was copied from the original message.

Running the sample

Run the sample, then press any key in the Sender window to send messages. The Receiver will execute two handlers. Note that the Sender and both Receiver handlers have access to the same CustomerId header.

Related Articles