Event Sourcing with EventFlow and Azure Cosmos DB

Luke Canvin

In our Dev Camp this year we chose to experiment with Event Sourcing, using EventFlow for the solution. One task was to configure it to use an Azure Cosmos database instead of a SQL Server one; the initial arrangement in one of the sample programs we started with was SQL via Entity Framework.

SQL via Entity Framework

EventFlow supports Entity Framework, as may be seen from the corresponding NuGet package:

NuGet package manager showing EventFlow.EntityFramework v0.74.3948 installed

It’s configured as follows:

Register method with eventFlowOptions configuration using EntityFramework configuration menthods

where EventStoreContext and EventStoreContextProvider are both set up to use SQL Server:

EventStoreContextProvider constructor with DbContextOptionsBuilder UseSqlServer configuration

The connection string is something like the usual

Server=SERVERNAME;Database=DBNAME;Integrated Security=SSPI

Azure Cosmos – take 1

The simplest option seemed to be to swap out SQL in favour of Cosmos in EventStoreContext and EventStoreContextProvider using the appropriate NuGet package:

NuGet package Microsoft.EntityFrameworkCore.Cosmos v2.2.0-preview3-35497 installed

and the code

EventStoreContextProvider constructor with new DbContextOptionsBuilder UseCosmos configuration

Unfortunately, this resulted in the following runtime error:

System.NotSupportedException message regarding GlobalSequenceNumber on entity type EventEntity

The combination of EventFlow and Entity Framework resulted in the need for the target database to have some distinctly SQL-like properties such as, in this instance, an identity column.

Azure Cosmos – take 2

This failure suggested an approach of bypassing Entity Framework and getting EventFlow to use a Cosmos database directly. Sadly …

NuGet package manager showing no packages found for EventFlow.Cosmos

EventFlow doesn’t support Cosmos databases (at least not yet).

Azure Cosmos – take 3

However, EventFlow can communicate with a Mongo database:

NuGet package EventFlow.MongoDB v0.74.3948 installed

and a Cosmos database can be treated as if it was a Mongo database. Here’s the first tab of the Azure Cosmos DB Emulator:

Azure Cosmos DB emulator showing Mongo Connection String

Using that, we were able to change from

Register method with eventFlowOptions configuration using EntityFramework configuration menthods

to

Register method with mongoDBConnectionString and eventFlowOptions using MongoDb configuration methods

with a little help from https://libraries.io/nuget/EventFlow.MongoDB.

This was successful and finally the application could connect to the Cosmos database without error.

Useful Resources

Event Flow Application

We used one from https://github.com/twzhangyang/RestAirline, although this was far from complete and working. It uses EventFlow’s support of Entity Framework to communicate with a SQL database.

Entity Framework and Cosmos

https://www.thereformedprogrammer.net/building-a-robust-cqrs-database-with-ef-core-and-cosmos-db/
uses a SQL Server write database and a Cosmos database for reading. However, it
wasn’t directly applicable to our desired architecture.

Event Flow Racetimes Example

https://github.com/dennisfabri/Eventflow.Example.Racetimes was a sample application in which Event Flow was used with a SQL database either via Entity Framework or directly. It was used as a testing ground to see if we could configure an application to use a Mongo database instead of a SQL one (neither via Entity Framework). This was a helpful halfway house when we were trying to reconfigure our application to

  • Not use Entity Framework and
  • Use a Mongo database instead of a SQL one

Gotchas

The Azure Cosmos DB Emulator provides a cost-free way to develop against a Cosmos database. As noted above, you can also connect to a Cosmos database as if it was a Mongo database – the appropriate connection string is provided by the emulator. However, this facility is turned off by default – you need to start the emulator with the EnableMongoDbEndpoint command line parameter to be able to use it.

The emulator also likes to claim that the cloud is a bit busy if you ask it to do something it doesn’t want to do:

"Sorry, we are currently experiencing high demand in this region, and cannot fulfil your request at this time. We work continuously to bring more and more capacity online, and encourage you to try again shortly."

It tends to do this irrespective of the actual cause (such as adding too many databases to your emulator).