# MongoDB Persistence ## Prerequisites Ensure an instance of [MongoDB](https://www.mongodb.com/) is running on `localhost:27017`. The easiest way to do this is to run MongoDB in Docker: ```shell docker run -d -p 27017:27017 --name TestMongoDB mongo:latest --replSet tr0 ``` ```shell docker exec -it TestMongoDB mongosh --eval ' rs.initiate({ _id: "tr0", members: [{ _id: 0, host: "localhost:27017" }] })' ``` Alternatively, it is possible to [install MongoDB](https://www.mongodb.com/docs/manual/installation/) but the instance must be part of a [replica set](https://www.mongodb.com/docs/manual/replication/) to enable transactions. If this is not possible, the endpoint configuration must be altered to disable transactions (not recommended for production): ```c# endpointConfiguration.UsePersistence().UseTransactions(false) ``` ### Data visualization To visualize data in MongoDB, install a [MongoDB visualization tool](https://www.mongodb.com/docs/tools-and-connectors/), such as [Compass](https://www.mongodb.com/try/download/compass). The screenshots in this sample are taken using Compass. ## Code walk-through This sample shows a simple client/server scenario: - `Client` sends a `StartOrder` message to `Server` - `Server` starts an `OrderSaga` instance - `OrderSaga` requests a timeout with `CompleteOrder` data - `CompleteOrder` timeout occurs and `OrderSaga` publishes an `OrderCompleted` event - `OrderCompleted` is delivered to `Client`, because `Client` is subscribed to that event - `Client` handles `OrderCompleted` ### MongoDB configuration The `Server` endpoint is configured to use MongoDB persistence. ```cs var endpointConfiguration = new EndpointConfiguration("Samples.MongoDB.Server"); var persistence = endpointConfiguration.UsePersistence(); persistence.DatabaseName("Samples_MongoDB_Server"); ``` - If a MongoDB URL is not specified, the persistence uses the default of `mongodb://localhost:27017`. - If a database name is not specified, the persistence uses the endpoint name as the database name. In this sample the database name is `Samples_MongoDB_Server`. ### Order saga ```cs public class OrderSaga(ILogger logger) : Saga, IAmStartedByMessages, IHandleTimeouts { protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper) { mapper.MapSaga(sagaData => sagaData.OrderId) .ToMessage(message => message.OrderId); } public Task Handle(StartOrder message, IMessageHandlerContext context) { Data.OrderId = message.OrderId; var orderDescription = $"The saga for order {message.OrderId}"; Data.OrderDescription = orderDescription; logger.LogInformation("Received StartOrder message {OrderId}. Starting Saga", Data.OrderId); logger.LogInformation("Order will complete in 5 seconds"); var timeoutData = new CompleteOrder { OrderDescription = orderDescription }; return RequestTimeout(context, TimeSpan.FromSeconds(5), timeoutData); } public Task Timeout(CompleteOrder state, IMessageHandlerContext context) { logger.LogInformation("Saga with OrderId {OrderId} completed", Data.OrderId); var orderCompleted = new OrderCompleted { OrderId = Data.OrderId }; MarkAsComplete(); return context.Publish(orderCompleted); } } ``` ### Saga data The saga data is stored in the `ordersagadata` collection. ```cs public class OrderSagaData : ContainSagaData { public Guid OrderId { get; set; } public string OrderDescription { get; set; } } ``` ![](sagadata.png) | Field | Maps to | |-------|---------| | `_id` | `IContainSagaData.Id` | | `Originator` | `IContainSagaData.Originator` | | `OriginalMessageId` | `IContainSagaData.OriginalMessageId` | | `OrderID` | `OrderSagaData.OrderID` | | `OrderDescription` | `OrderSagaData.OrderDescription` | | `_version` | Added and managed by the persistence to prevent concurrency issues |