Manipulating custom headers can be useful for storing infrastructure-level information not directly related to the business message. Instead of forcing all message types to inherit from a base class or implement a specific interface in order to force the existence of certain properties, instead consider moving this information into message headers.
Message headers are best manipulated through pipeline behaviors, however they can be accessed and modified from message handlers and saga handlers as well.
Depending on the message transport, headers are stored with the message either as native headers (if supported) or via a serialized collection of key/value pairs within the message body itself.
This article covers the various ways of manipulating the message headers.
Reading incoming headers
Headers can be read for an incoming message.
From a behavior
public class IncomingBehavior :
IBehavior<IncomingContext>
{
public void Invoke(IncomingContext context, Action next)
{
var headers = context.PhysicalMessage.Headers;
var nsbVersion = headers[Headers.NServiceBusVersion];
var customHeader = headers["MyCustomHeader"];
next();
}
}
From a mutator
public class MutateIncomingTransportMessages :
IMutateIncomingTransportMessages
{
public void MutateIncoming(TransportMessage transportMessage)
{
var headers = transportMessage.Headers;
var nsbVersion = headers[Headers.NServiceBusVersion];
var customHeader = headers["MyCustomHeader"];
}
}
From a handler
public class ReadHandler :
IHandleMessages<MyMessage>
{
IBus bus;
public ReadHandler(IBus bus)
{
this.bus = bus;
}
public void Handle(MyMessage message)
{
var headers = bus.CurrentMessageContext.Headers;
var nsbVersion = headers[Headers.NServiceBusVersion];
var customHeader = headers["MyCustomHeader"];
}
}
From a saga
public class ReadSaga :
Saga<ReadSagaData>,
IHandleMessages<MyMessage>
{
public void Handle(MyMessage message)
{
var headers = Bus.CurrentMessageContext.Headers;
var nsbVersion = headers[Headers.NServiceBusVersion];
var customHeader = headers["MyCustomHeader"];
}
Writing outgoing headers
Headers can be written for an outgoing message.
From a behavior
public class OutgoingBehavior :
IBehavior<OutgoingContext>
{
public void Invoke(OutgoingContext context, Action next)
{
var headers = context.OutgoingMessage.Headers;
headers["MyCustomHeader"] = "My custom value";
next();
}
}
From a mutator
public class MutateOutgoingTransportMessages :
IMutateOutgoingTransportMessages
{
public void MutateOutgoing(LogicalMessage logicalMessage, TransportMessage transportMessage)
{
var headers = transportMessage.Headers;
headers["MyCustomHeader"] = "My custom value";
}
}
From a handler
public class WriteHandler :
IHandleMessages<MyMessage>
{
IBus bus;
public WriteHandler(IBus bus)
{
this.bus = bus;
}
public void Handle(MyMessage message)
{
var someOtherMessage = new SomeOtherMessage();
bus.SetMessageHeader(
msg: someOtherMessage,
key: "MyCustomHeader",
value: "My custom value");
bus.Send(someOtherMessage);
}
}
From a saga
public class WriteSaga :
Saga<WriteSagaData>,
IHandleMessages<MyMessage>
{
public void Handle(MyMessage message)
{
var someOtherMessage = new SomeOtherMessage();
Bus.SetMessageHeader(
msg: someOtherMessage,
key: "MyCustomHeader",
value: "My custom value");
Bus.Send(someOtherMessage);
}
For all outgoing messages
NServiceBus supports registering headers at configuration time that are then added to all outgoing messages for the endpoint.
var startableBus = Bus.Create(busConfiguration);
startableBus.OutgoingHeaders.Add("AllOutgoing", "ValueAllOutgoing");
using (var bus = startableBus.Start())
{