CQRS
Installation
dotnet add package Genocs.CQRS
Dependencies
- Genocs.Core
Commands
Overview
Adds an ability to create and process commands in the sense of CQRS.
Usage
Implement ICommand
(marker) interface in the selected class. Since the command represents the userβs intention you should follow the convention:
- Keep all the commands immutable
- Name of your commands should be imperative
public class CreateAccount : ICommand
{
public Guid Id { get; }
public string Email { get; }
public string Password { get; }
public CreateUser(id, email, password)
{
Id = id;
Email = email;
Password = password;
}
}
Create dedicated command handler class that implements ICommandHandler<TCommand>
interface with HandleAsync()
method:
public class CreateAccountHandler : ICommandHandler<CreateAccount>
{
public Task HandleAsync(CreateAccount command)
{
//put the handling code here
}
}
You can easily register all command handlers in DI container by calling AddCommandHandlers()
method on IGenocsBuilder
:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddCommandHandlers();
//other registrations
return builder.Build();
}
Dispatching a particular command object can be also done using Genocs.Common
package. Start with registering in-memory dispatcher on your IGenocsBuilder
by calling a AddInMemoryCommandDispatcher()
method:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddCommandHandlers()
.AddInMemoryCommandDispatcher();
//other registrations
return builder.Build();
}
Then simply inject ICommandDispatcher
into a class and call DispatchAsync()
method:
public class AccountsService
{
private readonly ICommandDispatcher _dispatcher;
public AccountsService(ICommandDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public Task CreateAccountAsync(CreateAccount command)
=> _dispatcher.DispatchAsync(command);
}
Queries
Overview
Adds an ability to create and process queries in the sense of CQRS.
Usage
Implement IQuery<TResult>
interface in the selected class:
public class GetAccount : IQuery<AccountDto>
{
public Guid Id { get; set; }
}
Create dedicated query handler class that implements IQueryHandler<TQuery, TResult>
interface with HandleAsync()
method:
public class GetAccountHandler : IQueryHandler<GetAccount, AccountDto>
{
public Task<AccountDto> HandleAsync(GetAccount query)
{
//put the handling code here
}
}
You can easily register all query handlers in DI container by calling AddQueryHandlers()
method on IGenocsBuilder
:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddQueryHandlers();
//other registrations
return builder.Build();
}
Dispatching a particular query object can be also done using Genocs.Common
package. Start with registering in-memory dispatcher on your IGenocsBuilder
by calling a AddInMemoryQueryDispatcher()
method:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddQueryHandlers()
.AddInMemoryQueryDispatcher();
//other registrations
return builder.Build();
}
Then simply inject IQueryDispatcher
into a class and call DispatchAsync()
method:
public class AccountsService
{
private readonly IQueryDispatcher _dispatcher;
public AccountsService(IQueryDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public Task<AccountDto> GetAccountAsync(Guid id)
=> _dispatcher.DispatchAsync(new GetAccount { Id = id });
}
Events
Overview
Adds ability to create and process events in the sense of CQRS.
Usage
Implement IEvent
or IRejectedEvent
(marker) interface in the selected class. Since the event represents something that already happened, you should follow the convention:
- keep all the events immutable
- name of your events should kept in the past tense
public class AccountCreated : IEvent
{
public Guid Id { get; }
public AccountCreated(id)
{
Id = id;
}
}
Create dedicated event handler class that implements IEventHandler<TEvent>
interface with HandleAsync()
method:
public class AccountCreatedHandler : IEventHandler<AccountCreated>
{
public Task HandleAsync(AccountCreated @event)
{
//put the handling code here
}
}
You can easily register all event handlers in DI container by calling AddEventHandlers()
method on IGenocsBuilder
:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddEventHandlers();
//other registrations
return builder.Build();
}
Dispatching a particular event object can be also done using Genocs.Common
package. Start with registering in-memory dispatcher on your IGenocsBuilder
by calling a AddInMemoryEventDispatcher()
method:
public IServiceProvider ConfigureServices(this IServiceCollection services)
{
var builder = services
.AddGenocs()
.AddCommandHandlers()
.AddInMemoryEventDispatcher();
//other registrations
return builder.Build();
}
Then simply inject IEventDispatcher
into a class and call DispatchAsync()
method:
public class AccountsService
{
private readonly IEventDispatcher _dispatcher;
public AccountsService(IEventDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public Task PostProcessAccountCreation(AccountCreated @event)
=> _dispatcher.DispatchAsync(@event);
}