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.

Conventions

Component:
NServiceBus
NuGet Package:
NServiceBus 10.x

Conventions identify message, command, and event types without marker interfaces. Using conventions for message identification is called unobtrusive mode.

Currently, conventions exist to identify:

Message types can be defined in a Portable Class Library (PCL) and shared across multiple platforms, even if the platform does not use NServiceBus for message processing.

var conventions = endpointConfiguration.Conventions();
conventions.DefiningCommandsAs(type => type.Namespace == "MyNamespace.Messages.Commands");
conventions.DefiningEventsAs(type => type.Namespace == "MyNamespace.Messages.Events");
conventions.DefiningMessagesAs(type => type.Namespace == "MyNamespace.Messages");
conventions.DefiningClaimCheckPropertiesAs(property => property.Name.EndsWith("DataBus"));
conventions.DefiningTimeToBeReceivedAs(type => type.Name.EndsWith("Expires") ? TimeSpan.FromSeconds(30) : TimeSpan.MaxValue);

Using both default and custom conventions

Defining a custom convention will overwrite the default convention. If both default and custom conventions are needed, the default conventions must be specified along with the custom conventions.

var conventions = endpointConfiguration.Conventions();
conventions.DefiningCommandsAs(type =>
    type.Namespace == "MyNamespace.Messages.Commands"
    || typeof(ICommand).IsAssignableFrom(type)
);
conventions.DefiningEventsAs(type =>
    type.Namespace == "MyNamespace.Messages.Events"
    || typeof(IEvent).IsAssignableFrom(type)
);
conventions.DefiningMessagesAs(type =>
    type.Namespace == "MyNamespace.Messages"
    || typeof(IMessage).IsAssignableFrom(type)
);
conventions.DefiningClaimCheckPropertiesAs(property =>
    property.Name.EndsWith("DataBus")
    || typeof(IClaimCheckProperty).IsAssignableFrom(property.PropertyType) && typeof(IClaimCheckProperty) != property.PropertyType
);
conventions.DefiningTimeToBeReceivedAs(type =>
    type.Name.EndsWith("Expires")
        ? TimeSpan.FromSeconds(30)
        : type.GetCustomAttribute<TimeToBeReceivedAttribute>(false)?.TimeToBeReceived ?? TimeSpan.MaxValue
);

Encapsulated conventions

Messaging conventions can be encapsulated into a class.

class MyNamespaceMessageConvention : IMessageConvention
{
    public bool IsMessageType(Type type) => type.Namespace == "MyNamespace.Messages";
    public bool IsCommandType(Type type) => type.Namespace == "MyNamespace.Messages.Commands";
    public bool IsEventType(Type type) => type.Namespace == "MyNamespace.Messages.Events";
    public string Name { get; } = "MyNamespace message convention";
}

These conventions can be added to the endpoint.

endpointConfiguration.Conventions().Add(new MyNamespaceMessageConvention());

Multiple encapsulated conventions can be applied to the same endpoint. A class will be considered a message, command, or event if any convention matches it.

Attributes

If attributes are preferred over marker interfaces, use NServiceBus.AttributeConventions, a community package that allows using attributes instead of interfaces.

Related Articles

  • Messages, events, and commands
    Messages as commands or events are the the unit of communication for message-based distributed systems. NServiceBus ensures they are used correctly.
  • Unobtrusive Mode Messages
    How to avoid referencing NServiceBus assemblies from message assemblies.