﻿# Reading and writing message headers

<!-- Version variant: core_9; default: [/nservicebus/messaging/header-manipulation.md](/nservicebus/messaging/header-manipulation.md) -->


NServiceBus provides multiple ways to read and write the headers associated with each message. The same approach is used for [built-in NServiceBus headers](/nservicebus/messaging/headers.md) and for custom headers.

Custom headers are 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 to ensure the existence of certain properties, consider moving this information into message headers.

Message headers are best manipulated through [pipeline behaviors](/nservicebus/pipeline/manipulate-with-behaviors.md), however they can be accessed and modified from message handlers and saga handlers as well.

Depending on the [message transport](/transports/index.md), 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 to manipulate message headers.

## Reading incoming headers

Headers can be read for an incoming message.

### From a behavior

<!-- snippet: header-incoming-behavior -->

```cs
public class IncomingBehavior :
    Behavior<IIncomingPhysicalMessageContext>
{
    public override Task Invoke(IIncomingPhysicalMessageContext context, Func<Task> next)
    {
        var headers = context.Message.Headers;
        var nsbVersion = headers[Headers.NServiceBusVersion];
        var customHeader = headers["MyCustomHeader"];
        return next();
    }
}
```

<!-- endsnippet -->

### From a mutator

<!-- snippet: header-incoming-mutator -->

```cs
public class MutateIncomingTransportMessages :
    IMutateIncomingTransportMessages
{
    public Task MutateIncoming(MutateIncomingTransportMessageContext context)
    {
        var headers = context.Headers;
        var nsbVersion = headers[Headers.NServiceBusVersion];
        var customHeader = headers["MyCustomHeader"];
        return Task.CompletedTask;
    }
}
```

<!-- endsnippet -->

### From a handler

<!-- snippet: header-incoming-handler -->

```cs
public class ReadHandler :
    IHandleMessages<MyMessage>
{
    public Task Handle(MyMessage message, IMessageHandlerContext context)
    {
        var headers = context.MessageHeaders;
        var nsbVersion = headers[Headers.NServiceBusVersion];
        var customHeader = headers["MyCustomHeader"];
        return Task.CompletedTask;
    }
}
```

<!-- endsnippet -->

## Writing outgoing headers

Headers can be written for an outgoing message.

### From a behavior

<!-- snippet: header-outgoing-behavior -->

```cs
public class OutgoingBehavior :
    Behavior<IOutgoingPhysicalMessageContext>
{
    public override Task Invoke(IOutgoingPhysicalMessageContext context, Func<Task> next)
    {
        var headers = context.Headers;
        headers["MyCustomHeader"] = "My custom value";
        return next();
    }
}
```

<!-- endsnippet -->

### From a mutator

<!-- snippet: header-outgoing-mutator -->

```cs
public class MutateOutgoingTransportMessages :
    IMutateOutgoingTransportMessages
{
    public Task MutateOutgoing(MutateOutgoingTransportMessageContext context)
    {
        context.OutgoingHeaders["MyCustomHeader"] = "My custom value";
        return Task.CompletedTask;
    }
}
```

<!-- endsnippet -->

### From a handler

> [!NOTE]
> SendOptions is meant for custom headers - changes to NServiceBus headers may be overwritten.

<!-- snippet: header-outgoing-handler -->

```cs
public class WriteHandler :
    IHandleMessages<MyMessage>
{
    public async Task Handle(MyMessage message, IMessageHandlerContext context)
    {
        var sendOptions = new SendOptions();
        sendOptions.SetHeader("MyCustomHeader", "My custom value");
        await context.Send(new SomeOtherMessage(), sendOptions);

        var replyOptions = new ReplyOptions();
        replyOptions.SetHeader("MyCustomHeader", "My custom value");
        await context.Reply(new SomeOtherMessage(), replyOptions);

        var publishOptions = new PublishOptions();
        publishOptions.SetHeader("MyCustomHeader", "My custom value");
        await context.Publish(new SomeOtherMessage(), publishOptions);
    }
}
```

<!-- endsnippet -->

### For all outgoing messages

NServiceBus supports registering headers at configuration time that are then added to all outgoing messages for the endpoint.

<!-- snippet: header-static-endpoint -->

```cs
endpointConfiguration.AddHeaderToAllOutgoingMessages("MyGlobalHeader", "some static value");
```

<!-- endsnippet -->
