Startup
class and modify it so that it inherits from RevoStartup
. This adds a light-weight support for the ASP.NET Core platform and bootstraps the framework application.CreateRevoConfiguration()
which configures the framework. This is the place to modify many of configuration options the framework offers.TodoList
), which is also the aggregate root, represents an entry point to interacting with the aggregate.[DomainClassId]
attribute. This is an arbitrary GUID value (that must however be unique in your project) and is needed by Revo to identify the class when saving the aggregate.ICommand
interface. Same as with events, we make its properties immutable. A single command always represents one write operation. Its scope can vary greatly depending on the needs of your consumers (here a future REST API that we are going to write), but it is usually a good practice that one command should always modify just one aggregate.[Required]
validation attribute, which ensures that only commands with non-empty data can get passed to the command handlers.ICommandHandler<>
interfaces. By default, these handlers get auto-discovered and registered upon application startup, so it is enough to just define the class.[TablePrefix]
attribute is just Revo's convenience attribute which prefixes the names of the tables and columns and you don't need to use it if you don't like it.GetTodoListsQuery
loosely corresponds to a single REST API endpoint we are going to implement.IQuery<T>
interface, where T
is the type of the result it returns. It can also have parameters (properties) like commands.IReadRepository
(CRUD repository) instead of IRepository
(domain repository).IRepository
in command handlers to modify your aggregates, in your query handlers, you are going to need IReadRepository
which is just a thin read-only abstraction layer over an ORM (Entity Framework Core here in our case).IReadRepository
(which behaves just like a thin wrapper over an CRUD-like ORM), domain IRepository
can also persist aggregates in other forms, e.g. event sourced aggregates to an event store. It also deals with other aspects of domain aggregates like publishing events to event bus.CommandApiController
which does just one thing - gets an ICommandBus
dependency injected. A command bus can be used for sending commands and queries to an application.