Command Handling - Code Example - Server


When building systems using event sourcing, commands can be handled either client side or exposed via an API and handled on the server side.

In this article I'll cover how I build command handling on the server, using c#.

As a quick reminder: Command handling is the common name for the steps on the left hand side of the cqrs architecture.

Server Side Command Handling

Roster Management

The scenario used for this example will be consistent with the client side examples, we are going to create a team roster for next season.

Roster Management

If you want to catch up on the scenario, check out the original description in the client side command handling post.

The command

As dotnet is a typed environment, we need to create a class for the create roster command that we'll expose through our API.

public class CreateRoster
    public string RosterId { get; set; }

    public string Name { get; set; }


The command handler is exposed as an HTTP POST operation on an MVC controller.

public class RosterCreation : Controller
    private readonly EventSourcedRepository _repository;

    public RosterCreation(EventSourcedRepository repository)
        _repository = repository;

    public async Task<IActionResult> Handle([FromRoute] string id, [FromBody] CreateRoster cmd)
        var aggregate = await _repository.Get<Roster>(cmd.RosterId);

        aggregate.Create(User, cmd.Name);

        await _repository.Flush();

        return Ok();

The command handler has a dependency on EventSourcedRepository which is a generic repository that mediates between the aggregate root Roster and the underlying event source.

The repository creates a Roster instance for the given roster id, loads any preexisting events, and passes those into the roster for restoration of its internal state.

Once restored, command handling is delegated to the aggregate root instance.

The aggregate root might emit events in as a result of handling the command, these events will be stored in the event source when the repository is flushed.

The aggregate root

Ultimately the aggregate root pattern is responsible for taking a decission based on the presented command.

It decides whether the command will be acted upon and how.

It communicates the resulting decission through an event, if the decission is considered business wise meaningful.

public class Roster : EventSourced,
    public Roster(string id) : base(id){ }

    public void Create(ClaimsPrincipal user, string name)
        if (_name != null) return;

        Emit(new RosterCreated()
            Context = new Context
                Id = Id,
                What = nameof(RosterCreated),
                When = DateTime.UtcNow,
                Who = user?.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Id)?.Value
            RosterId = Id,
            Name = name               
        }) ;

    public void Apply(RosterCreated msg)
        _name = msg.Name;

    private string _name; 

Usually the aggregate requires the decissions it has taken in the past as input for any future decission.

The IApply<T> implementation allows to restore inner state based on previously emitted events.

These methods will be called via the EventSourced base class in response to the EventSourcedRepository loading and passing in historical events.

The Create method first validates if it hasn't been invoked before, it does so by checking it's internal name property.

This check is purely for idempotency reasons and not considered meaningful, therefor it does not emit an event.

If it hasn't been invoked before, it emits a new RosterCreated event.

For completeness, the RosterCreated event has been defined with the following properties.

public class RosterCreated : SourcedEvent
    public Context Context { get; set; }
    public string RosterId { get; set; }
    public string Name { get; set; }

As you can see, it also inherits from SourcedEvent, this class contains some base properties required for the eventsourcing infrastructure to work.


On the client side, I needed to create a custom event store and custom repository, just to coordinate loading and flushing events back to the API (more on this in a future post).

I also had to set a couple of properties, just because javascript isn't a typed language.

On the server however none of that is needed, all the infrastructure needs is a connectionstring to an azure table storage account and a table name.

Everything else can be derived from the type system and the base classes.

public static IServiceCollection AddEventSource(this IServiceCollection services)
    var connectionString = Environment.GetEnvironmentVariable("CUSTOMCONNSTR_azure-storage-data");

    var configuration = new EventsourcingConfiguration();

    var eventSource = new AzureTableStorageEventSource(connectionString, "Rosters");

    return services;


Plugging the infrastructure in happens at startup, typically in the ConfigureServices callback provided by the asp.net mvc infrastructure.

public void ConfigureServices(IServiceCollection services)


Handling a command on the server is a very common scenario, often combined with the store and forward pattern on the client though, and not with client side event sourcing.

Only when there are different clients with different online/offline characteristics it is possible that events emitted from the client need to be integrated with events emitted on the server.

Back to guide

This article is part of the building offline progressive web apps guide. Return to this guide to explore more aspects of building offline progressive web apps.

About the author


I love to build web and cloud apps and have been doing so for the past 20 years.

My main areas of expertise are progressive web applications, event driven architecture, domain driven design, event sourcing, messaging, and Microsoft Azure.

Through this blog I hope to share some of this experience with you.

Get in touch

Sign up to my newsletter to get notified about new content

You can unsubscribe at any time by clicking the link in the footer of your emails. I use Mailchimp as my marketing platform. By clicking subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.