Commands and queries
The framework implements a number of facilities for working with commands, queries and for implementing CQRS.
Commands, queries
Commands and queries can be defined as regular POCO classes implementing ICommand
or IQuery<T>
(with T
defining the query return type) interfaces. These interfaces are empty on their own and only define the contract of being processable by a command bus.
Because both IQuery
and ICommand
derive from a common ICommandBase
ancestor, the framework considers queries to be simply a specific subtype of commands that happen to also return a value.
Example command:
Example query:
It is advisable to make the command/query classes immutable (as can be seen in the example) to prevent undesirable modifications as the object gets passed throughout the system.
Command/query handlers
Commands and queries can be handled by implementing ICommandHandler<TCommand>
or IQueryHandler<TQuery, TResult>
respectively. For every command or query type, there should be exactly one handler type registered in the dependency container, otherwise an exception will be thrown when trying to handle it.
By default, all command and query handlers get auto-discovered in all referenced assemblies and registered in task scope.
Command bus
To send a command or query to the system, one can use an ICommandBus
which encapsulates most of the command processing details.
The command bus is designed to accept any command or query type an resolves the corresponding handlers during runtime. By default, the command handling also starts a new unit of work that is automatically committed at the end of the handling pipeline – to find more about this, see chapter describing the request life-cycle.
Command filters
Command filters provide a way for dealing with cross-cutting concerns when handling their execution. It is possible to define action that will get executed before invoking a command handler, after invoking it and after invoking it in case it results in an error exception.
These filters get automatically invoked when registered in the dependency container for a specific command (base) type. The framework uses them to deal with concerns like authorization or automatic unit-of-work management, but it is also possible to define custom application’s own filters.
Last updated