# MongoDB

MongoDB is easy to setup as a saga repository. MassTransit includes sensible defaults, and there is no need to explicitly map sagas.

Storing a saga in MongoDB requires an additional interface, ISagaVersion, which has a Version property used for optimistic concurrency. An example saga is shown below.

namespace PersistedSaga
{
    using System;
    using MassTransit.Saga;
    using Automatonymous;

    public class OrderState :
        SagaStateMachineInstance,
        ISagaVersion
    {
        public Guid CorrelationId { get; set; }
        public string CurrentState { get; set; }

        public DateTime? OrderDate { get; set; }

        public int Version { get; set; }
    }
}

# Configuration

To configure MongoDB as a saga repository, use the code shown below using the AddMassTransit container extension. This will configure MongoDB to connect to the local MongoDB instance on the default port using Optimistic concurrency. The CorrelationId property will be automatically mapped to be the document identifier.

namespace MongoDbSagaContainer
{
    using System;
    using MassTransit;
    using Microsoft.Extensions.DependencyInjection;
    using PersistedSaga;

    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddMassTransit(x =>
            {
                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .MongoDbRepository(r =>
                    {
                        r.Connection = "mongodb://127.0.0.1";
                        r.DatabaseName = "orderdb";
                    });
            });
        }
    }
}

In the example above, saga instances are stored in a collection named order.states. The collection name can be specified using the CollectionName property. Alternatively, a collection name formatter can be specified using the CollectionNameFormatter method.

namespace MongoDbSaga
{
    using System;
    using MassTransit;
    using MassTransit.MongoDbIntegration;
    using Microsoft.Extensions.DependencyInjection;
    using PersistedSaga;

    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddMassTransit(x =>
            {
                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .MongoDbRepository(r =>
                    {
                        r.Connection = "mongodb://127.0.0.1";
                        r.DatabaseName = "orderdb";

                        r.CollectionName = "orders";
                    });
            });
        }
    }
}

Container integration gives you ability to configure class map based on saga type. You can use Action<BsonClassMap> explicitly:

namespace MongoDbSagaClassMap
{
    using System;
    using MassTransit;
    using MassTransit.MongoDbIntegration;
    using Microsoft.Extensions.DependencyInjection;
    using PersistedSaga;

    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddMassTransit(x =>
            {
                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .MongoDbRepository(r =>
                    {
                        r.Connection = "mongodb://127.0.0.1";
                        r.DatabaseName = "orderdb";

                        r.ClassMap(m => {});
                    });
            });
        }
    }
}

BsonClassMap<TSaga> registered inside container will be used by default for TSaga configuration:

namespace MongoDbSagaRegisterClassMap
{
    using System;
    using MassTransit;
    using Microsoft.Extensions.DependencyInjection;
    using MongoDB.Bson.Serialization;
    using MongoDB.Bson.Serialization.Serializers;
    using PersistedSaga;

    class OrderStateClassMap :
        BsonClassMap<OrderState>
    {
        public OrderStateClassMap()
        {
            MapProperty(x => x.OrderDate)
                .SetSerializer(new DateTimeSerializer(DateTimeKind.Utc));
        }
    }


    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddSingleton<BsonClassMap<OrderState>, OrderStateClassMap>();

            services.AddMassTransit(x =>
            {
                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .MongoDbRepository(r =>
                    {
                        r.Connection = "mongodb://127.0.0.1";
                        r.DatabaseName = "orderdb";
                    });
            });
        }
    }
}