Command Handling with MassTransit¶
Like MediatR, MassTransit sits in front of EventSourcingKit and turns commands into events. The difference is the transport: MassTransit dispatches commands as messages over a bus, which lets a handler run in process today and move out of process later without changing its shape.
Commands, not events
This page is about handling commands with MassTransit. MassTransit is used here as a request/response command bus; the resulting events are stored and observed by EventSourcingKit itself. To forward events outward through a broker, see Publishing Events.
The Pattern¶
A command is a plain message, paired with a result. Its handler is an IConsumer that injects IEventStore, stores the events, and replies with RespondAsync:
public record RegisterBookCommand(string Title, string Author);
public record RegisterBookCommandResult(Guid BookId);
public class RegisterBookCommandHandler(IEventStore eventStore)
: IConsumer<RegisterBookCommand>
{
public async Task Consume(ConsumeContext<RegisterBookCommand> context)
{
var command = context.Message;
var bookId = Guid.CreateVersion7();
var subject = new Subject($"/books/{bookId}");
var candidate = new EventCandidate(
subject,
new BookRegistered(bookId, command.Title, command.Author)
);
await eventStore.StoreEvents(
[candidate],
[new IsSubjectPristinePrecondition(subject)],
context.CancellationToken
);
await context.RespondAsync(new RegisterBookCommandResult(bookId));
}
}
Registration¶
Register MassTransit, add your consumers and a request client for each command, and choose a transport. The in-memory transport keeps everything in process, which is ideal to start with:
builder.Services.AddMassTransit(c =>
{
c.AddConsumer<RegisterBookCommandHandler>();
c.AddRequestClient<RegisterBookCommand>();
c.UsingInMemory((context, busConfigurator) =>
busConfigurator.ConfigureEndpoints(context)
);
});
A caller then sends the command through an IRequestClient<RegisterBookCommand> and awaits the RegisterBookCommandResult.
For More Information¶
- Storing Events and Preconditions explains the write the consumer performs.
- Publishing Events covers forwarding events outward to a broker.
- Exposing an API shows a GraphQL mutation dispatching a MassTransit command.