Messages, events and commands

Component: NServiceBus
NuGet Package NServiceBus (8-pre)
This page targets a pre-release version. Pre-releases are subject to change and samples are not guaranteed to be fully functional.

A message is the unit of communication for NServiceBus. There are two types of messages, commands and events, that capture more of the intent and help NServiceBus enforce messaging best practices. This enforcement is enabled by default, but can be disabled.

CommandEvent
Used to make a request to perform an action.Used to communicate that an action has been performed.
Has one logical owner.Has one logical owner.
Should be sent to the logical owner.Should be published by the logical owner.
Cannot be published.Cannot be sent.
Cannot be subscribed to or unsubscribed from.Can be subscribed to and unsubscribed from.
Can be sent using the gateway.Cannot be sent using the gateway.
In a request and response pattern, reply messages are neither a command nor an event.

Validation

There are checks in place to ensure best practices are followed. Violations of the above guidelines generate the following exceptions:

  • "Pub/Sub is not supported for Commands. They should be sent direct to their logical owner." - this exception is being thrown when attempting to publish a Command or subscribe to/unsubscribe from a Command.
  • "Events can have multiple recipient so they should be published." - this exception will occur when attempting to use 'Send()' to send an event.
  • "Reply is neither supported for Commands nor Events. Commands should be sent to their logical owner using bus.Send and bus. Events should be published." - this exception is thrown when attempting to reply with a Command or an Event.
  • "Cannot configure routing for type because it is not considered a message. Message types have to either implement NServiceBus.IMessage interface or match a defined message convention." - this exception is thrown when configuring destination endpoint for a non-message type.
  • "Cannot configure routing for assembly because it contains no types considered as messages. Message types have to either implement NServiceBus.IMessage interface or match a defined message convention." - this exception is thrown when configuring destination endpoint for an assembly which contains no types considered messages.
  • "Cannot configure routing for namespace because it contains no types considered as messages..." - this exception is thrown when configuring destination endpoint for a namespace which contains no types considered messages.
  • "Cannot configure publisher for type because it is not considered a message. Message types have to either implement NServiceBus.IMessage interface or match a defined message convention." - this exception is thrown when configuring publisher for a type that is not a message.
  • "Cannot configure publisher for type because it is not considered an event. Event types have to either implement NServiceBus.IEvent interface or match a defined event convention." - this exception is thrown when configuring publisher for a type that is not an event.
  • "Cannot configure publisher for type because it is a command." - this exception is thrown when configuring publisher for a command.

Designing messages

Messages represent data contracts between endpoints. They should be designed according to the following guidelines.

Messages should:

  • be simple POCO types.
  • be as small as possible.
  • satisfy the Single Responsibility Principle. Types used for other purposes (e.g. domain objects, data access objects, or UI binding objects) should not be used as messages.
Prior to NServiceBus version 7.2, messages had to be defined as a class. Defining them as a struct would result in a runtime exception.

Generic message definitions (e.g. MyMessage<T>) are not supported. It is recommended to use dedicated, simple types for each message or to use inheritance to reuse shared message characteristics.

Solution structure

Messages define the data contract between two endpoints.

It's recommended to use a dedicated assembly for message contracts. By keeping message contracts in a separate assembly, the amount of information and dependencies shared between services is minimized. It is recommended to have a separate message assembly for every service. When doing so, a service can evolve its contracts without impacting other services in the system. Every message contract should be declared in the contracts assembly of the service owning that message contract.

Consideration should be given to how the contracts assembly will be used by services. When certain events are subscribed to by multiple endpoints managed by other teams, it might make sense to extract those contracts into a separate NuGet package. Depending on the usage and the frequency of changes, separating contracts into multiple assemblies might decouple these contracts and minimize the impact of the changes.

It's also possible to share messages as C# source files without packaging them into an assembly. One advantage of this approach is that messages don't need to be compiled against specific NServiceBus versions, which means that assembly redirects are redundant. This can also be accomplished through the use of unobstrusive mode.

Identifying messages

Endpoints will process any message that can be deserialized into a .NET type but requires message contracts to be identified up front to support:

Messages can be defined either by implementing a marker interface or by specifying a custom convention.

Marker interfaces

The simplest way to identify messages is to use interfaces.

  • NServiceBus.ICommand for a command.
  • NServiceBus.IEvent for an event.
  • NServiceBus.IMessage for any other type of message (e.g. a reply in a request response pattern).
public class MyCommand : ICommand { }

public class MyEvent : IEvent { }

public class MyMessage : IMessage { }

Conventions

To avoid having message contract assemblies reference the NServiceBus assembly, custom conventions can be used to identify the types used as contracts for messages, commands, and events. This is known as unobtrusive mode.

Related Articles


Last modified