Super-short example
So how does it actually look when writing an application with Revo?
These few following paragraphs show how could one design super-simple application that can save tasks using event-sourced aggregates and then query them back from a RDBMS.
A little-bit more complete application based on this code, along with some walkthrough, can be found in the Task list app example.

The event that happens when changing a task's name.
public class TodoRenamedEvent : DomainAggregateEvent
{
public TodoRenamedEvent(string name)
{
Name = name;
}
public string Name { get; }
}

The task aggregate root.
public class Todo : EventSourcedAggregateRoot
{
public Todo(Guid id, string name) : base(id)
{
Rename(name);
}
protectedTodo(Guid id) : base(id)
{
}
public string Name { get; private set; }
public void Rename(string name)
{
if (!Name != name)
{
Publish(new TodoRenamedEvent(name));
}
}
private void Apply(TodoRenamedEvent ev)
{
Name = ev.Name;
}
}

Command to save a new task.
public class CreateTodoCommand : ICommand
{
public CreateTodoCommand(string name)
{
Name = name;
}
[Required]
public string Name { get; }
}
public class TodoCommandHandler : ICommandHandler<CreateTodoCommand>
{
private readonly IRepository repository;
public TodoCommandHandler(IRepository repository)
{
this.repository = repository;
}
public Task HandleAsync(CreateTodoCommand command, CancellationToken cancellationToken)
{
var todo = new Todo(command.Id);
todo.Rename(command.Name);
repository.Add(todoList);
return Task.CompletedTask;
}
}

Read model and a projection for the event-sourced aggregate.
public class TodoReadModel : EntityReadModel
{
public string Name { get; set; }
}
public class TodoListReadModelProjector : EFCoreEntityEventToPocoProjector<Todo, TodoReadModel>
{
public TodoListReadModelProjector(IEFCoreCrudRepository repository) : base(repository)
{
}
private void Apply(IEventMessage<TodoRenamedEvent> ev)
{
Target.Name = ev.Event.Name;
}
}

Query to read the tasks back from a RDBMS.
public class GetTodosQuery : IQuery<IQueryable<TodoReadModel>>
{
}
public class TaskQueryHandler : IQueryHandler<GetTodoQuery, IQueryable<TodoReadModel>>
{
private readonly IReadRepository readRepository;
public TaskListQueryHandler(IReadRepository readRepository)
{
this.readRepository = readRepository;
}
public Task<IQueryable<TodoReadModel>> HandleAsync(GetTodoListsQuery query, CancellationToken cancellationToken)
{
return Task.FromResult(readRepository
.FindAll<TodoListReadModel>());
}
}

Or just any arbitrary endpoint from where to send the command and queries from. :)
[Route("todos")]
public class TodoController : CommandApiController
{
[HttpGet("")]
public Task<IQueryable<TodoReadModel>> Get()
{
return CommandBus.SendAsync(new GetTodosQuery());
}
[HttpPost("")]
public Task Post([FromBody] CreateTodoDto payload)
{
return CommandBus.SendAsync(new CreateTodoCommand(payload.Name));
}
public class CreateTodoDto
{
public string Name { get; set; }
}
}

Now you are ready save the TO-DOs to an event store and read them from regular RDBMS read models.
Copy link
On this page
Event
Aggregate
Command and command handler
Read model and projection
Query and query handler
ASP.NET Core controller
Finish!