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.

Event

The event that happens when changing a task's name.
1
public class TodoRenamedEvent : DomainAggregateEvent
2
{
3
public TodoRenamedEvent(string name)
4
{
5
Name = name;
6
}
7
8
public string Name { get; }
9
}
Copied!

Aggregate

The task aggregate root.
1
public class Todo : EventSourcedAggregateRoot
2
{
3
public Todo(Guid id, string name) : base(id)
4
{
5
Rename(name);
6
}
7
8
protectedTodo(Guid id) : base(id)
9
{
10
}
11
12
public string Name { get; private set; }
13
14
public void Rename(string name)
15
{
16
if (!Name != name)
17
{
18
Publish(new TodoRenamedEvent(name));
19
}
20
}
21
22
private void Apply(TodoRenamedEvent ev)
23
{
24
Name = ev.Name;
25
}
26
}
Copied!

Command and command handler

Command to save a new task.
1
public class CreateTodoCommand : ICommand
2
{
3
public CreateTodoCommand(string name)
4
{
5
Name = name;
6
}
7
8
[Required]
9
public string Name { get; }
10
}
Copied!
1
public class TodoCommandHandler : ICommandHandler<CreateTodoCommand>
2
{
3
private readonly IRepository repository;
4
5
public TodoCommandHandler(IRepository repository)
6
{
7
this.repository = repository;
8
}
9
10
public Task HandleAsync(CreateTodoCommand command, CancellationToken cancellationToken)
11
{
12
var todo = new Todo(command.Id);
13
todo.Rename(command.Name);
14
repository.Add(todoList);
15
return Task.CompletedTask;
16
}
17
}
Copied!

Read model and projection

Read model and a projection for the event-sourced aggregate.
1
public class TodoReadModel : EntityReadModel
2
{
3
public string Name { get; set; }
4
}
Copied!
1
public class TodoListReadModelProjector : EFCoreEntityEventToPocoProjector<Todo, TodoReadModel>
2
{
3
public TodoListReadModelProjector(IEFCoreCrudRepository repository) : base(repository)
4
{
5
}
6
7
private void Apply(IEventMessage<TodoRenamedEvent> ev)
8
{
9
Target.Name = ev.Event.Name;
10
}
11
}
Copied!

Query and query handler

Query to read the tasks back from a RDBMS.
1
public class GetTodosQuery : IQuery<IQueryable<TodoReadModel>>
2
{
3
}
Copied!
1
public class TaskQueryHandler : IQueryHandler<GetTodoQuery, IQueryable<TodoReadModel>>
2
{
3
private readonly IReadRepository readRepository;
4
5
public TaskListQueryHandler(IReadRepository readRepository)
6
{
7
this.readRepository = readRepository;
8
}
9
10
public Task<IQueryable<TodoReadModel>> HandleAsync(GetTodoListsQuery query, CancellationToken cancellationToken)
11
{
12
return Task.FromResult(readRepository
13
.FindAll<TodoListReadModel>());
14
}
15
}
Copied!

ASP.NET Core controller

Or just any arbitrary endpoint from where to send the command and queries from. :)
1
[Route("todos")]
2
public class TodoController : CommandApiController
3
{
4
[HttpGet("")]
5
public Task<IQueryable<TodoReadModel>> Get()
6
{
7
return CommandBus.SendAsync(new GetTodosQuery());
8
}
9
10
[HttpPost("")]
11
public Task Post([FromBody] CreateTodoDto payload)
12
{
13
return CommandBus.SendAsync(new CreateTodoCommand(payload.Name));
14
}
15
16
public class CreateTodoDto
17
{
18
public string Name { get; set; }
19
}
20
}
Copied!

Finish!

Now you are ready save the TO-DOs to an event store and read them from regular RDBMS read models.
Last modified 1yr ago