Skip to content

Set up MongoDB persistence in Cratis Arc

Add Cratis.Arc.MongoDB when an Arc command or query needs to read or write MongoDB documents. This setup connects your host to a database and makes typed collections available through dependency injection. It does not require Chronicle or event sourcing.

Start from a working ASP.NET Core Arc host or lightweight Arc host, then install:

Terminal window
dotnet add package Cratis.Arc.MongoDB

The package references the ASP.NET shared framework as well as Arc Core, so that framework must be available to your host.

In your host’s appsettings.json, add:

{
"Cratis": {
"MongoDB": {
"Server": "mongodb://localhost:27017",
"Database": "library"
}
}
}

Server and Database are required. Keep production credentials in your host’s secret configuration, not source control. DirectConnection is optional: when unset, the connection string’s setting is preserved. Direct connection does not turn a standalone MongoDB server into a replica set.

This is a complete ASP.NET Core Program.cs for a project using Microsoft.NET.Sdk.Web with Cratis.Arc and Cratis.Arc.MongoDB installed. Use the settings above and a reachable MongoDB deployment.

using Cratis.Arc;
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
builder.AddCratisArc(configureBuilder: arc => arc.WithMongoDB());
var app = builder.Build();
app.UseCratisArc();
app.Run();

WithMongoDB() works through IArcBuilder, including the lightweight host’s AddCratisArc configuration callback. Retain that host’s normal build, UseCratisArc(), and run sequence. For existing ASP.NET/generic-host code, UseCratisMongoDB() remains an alternative registration entry point; do not register both paths.

To check registration, resolve IMongoCollection<T> from a request or service scope, with T replaced by your document type. Then read a collection you can access. Resolving the service checks dependency injection; a read checks connectivity and permissions too. Starting the host does not populate collections.

Registration supplies these defaults for collection access and BSON, MongoDB’s binary document format:

  • Scoped IMongoClient, IMongoDatabase, and IMongoCollection<T> access.
  • Default server/database resolvers and unchanged type/member naming.
  • Guid serialization using GuidRepresentation.Standard.
  • Concept, date/time, geometry, and other BSON serializers.
  • Discovered class maps, convention packs, and filters.

Choose naming and serialization rules before writing documents. They are initialized once for the process, not customized per request. For example, DateTimeOffset uses BSON UTC milliseconds by default, so stored values lose the original offset and submillisecond precision.

To store collection and member names in camel case, use this alternative registration:

builder.AddCratisArc(configureBuilder: arc => arc.WithMongoDB(
configureMongoDB: mongo => mongo.WithCamelCaseNamingPolicy()));

Import Cratis.Arc.MongoDB for MongoDB builder customization methods. Use WithServerResolver<T>() and WithDatabaseResolver<T>() only when the default configured server and tenant database naming do not meet your requirements.

EnableResilience defaults to true. Leave it enabled for Cosmos DB and when opening change streams before a collection exists. On async (Task-returning) collection calls, it handles “Collection not found” errors by returning success, default values, or empty cursors as appropriate. A change stream instead receives a cursor that waits for the collection.

Synchronous calls bypass this behavior. Async calls have a per-method concurrency limit of half the driver’s connection pool; waiting longer than one second for a slot raises TimeoutException. This option controls collection access, not retries or ahead-of-time (AOT) compilation.

For workloads that need plain driver behavior, add this setting alongside your required Server and Database values:

{
"Cratis": {
"MongoDB": {
"EnableResilience": false
}
}
}

Alternatively, configure the option when adding MongoDB to Arc (with the normal connection configuration already available). The callback takes precedence over configuration:

builder.AddCratisArc(configureBuilder: arc => arc.WithMongoDB(
configureOptions: options => options.EnableResilience = false));

With resilience disabled, you receive native exceptions and cancellation, the driver owns retries, and Arc adds no concurrency limit. Database and collection objects come directly from the driver. In either mode, disposing the root client does not dispose the process-shared client; disposing a request scope cannot invalidate later scopes. Derived clients returned by WithReadConcern, WithReadPreference or WithWriteConcern retain native driver behavior and ownership.

When Trace logging is enabled for MongoDBClientFactory at startup, Arc logs command start and completion metadata: request id, command name, database, collection, duration, and, for failures, the exception type and server error code. It does not log document, update or filter values, nor the driver’s failure message, because duplicate-key messages echo the key values.

To see full command bodies and failure messages while diagnosing a problem, opt in:

{
"Cratis": {
"MongoDB": {
"LogCommandBodies": true
}
}
}

Once ordinary reads work, check your document representations with concept serialization and class mapping. To keep query results live, continue with collection observation. Change streams require a replica set or sharded cluster with database-level watch and read permissions; a standalone server is not sufficient.