AI agents: use the documentation index at llms.txt to locate machine-readable pages. This section is indexed by https://docs.particular.net/nservicebus/llms.txt. The markdown version of this page is served as plain text. An MCP server at /mcp serves the same content via the search_docs and read_doc tools; it is read-only and needs no credentials. Markdown versions of documentation pages are available by appending .md to the page URL. Directory URLs use index.md. They are served as text/plain because some retrieval backends reject text/markdown.

Immutable Messages

Component:
NServiceBus

Messages are usually designed as DTOs, i.e. a plain class with public properties that can be read and changed. This model is simple and will always work. An alternative is immutable messages, which follow the coding philosophy that a message should not change once it has been created.

Message objects can be made immutable at runtime by:

  1. Using record types.
  2. Using properties with only public getters and initializing them via constructors.
  3. Using a regular message class with public getters and setters on the sender side, which implements an interface that has only public getters. Receivers reference only the interface.

Record types

Record types are the simplest way to create an immutable message. Their properties are set when the record is created and cannot be changed afterward.

public record CancelOrder(int OrderId);

Properties with only public getters

Properties can be made read-only from outside the class by giving them a public getter and a private setter, with values set through the constructor.

public class CancelOrder : ICommand
{
    public CancelOrder(int orderId)
    {
        OrderId = orderId;
    }

    public int OrderId { get; private set; }
}

Classes with public setters, interfaces with only getters

Using private setters is not supported by all serializers. An alternative is to make use of NServiceBus's support for multiple inheritance and polymorphic dispatch. With this approach, the message contract is defined as an interface that contains only getters, and the message handler uses that interface. The sender creates the message using a class that implements the interface and exposes public setters, then passes it to Send or Publish.

public class CancelOrder : ICancelOrder
{
    public CancelOrder(int orderId)
    {
        OrderId = orderId;
    }

    public int OrderId { get; set; } // Public setter
}

public interface ICancelOrder : IMessage
{
    int OrderId { get; } // Only getter
}

List of Samples