using System.Text.Json;
using Elsa.Features.Abstractions;
using Elsa.Features.Services;
using Elsa.KeyValues.Entities;
using Elsa.MongoDb.Contracts;
using Elsa.MongoDb.NamingStrategies;
using Elsa.MongoDb.Options;
using Elsa.MongoDb.Serializers;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Runtime.Entities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using MongoDB.Driver.Core.Extensions.DiagnosticSources;
namespace Elsa.MongoDb.Features;
///
/// Configures MongoDb.
///
public class MongoDbFeature : FeatureBase
{
///
public MongoDbFeature(IModule module) : base(module)
{
}
///
/// The MongoDB connection string.
///
public string ConnectionString { get; set; } = default!;
///
/// A delegate that configures MongoDb.
///
public Action Options { get; set; } = _ => { };
///
/// A delegate that creates an instance of an implementation of .
///
public Func CollectionNamingStrategy { get; set; } = sp => sp.GetRequiredService();
///
public override void Apply()
{
Services.Configure(Options);
var mongoUrl = new MongoUrl(ConnectionString);
Services.AddSingleton(sp => CreateMongoClient(sp, mongoUrl));
Services.AddScoped(sp => CreateDatabase(sp, mongoUrl));
Services.TryAddScoped();
Services.AddScoped(CollectionNamingStrategy);
RegisterSerializers();
RegisterClassMaps();
}
private static void RegisterSerializers()
{
TryRegisterSerializerOrSkipWhenExist(typeof(object), new PolymorphicSerializer());
TryRegisterSerializerOrSkipWhenExist(typeof(Type), new TypeSerializer());
TryRegisterSerializerOrSkipWhenExist(typeof(Variable), new VariableSerializer());
TryRegisterSerializerOrSkipWhenExist(typeof(Version), new VersionSerializer());
TryRegisterSerializerOrSkipWhenExist(typeof(JsonElement), new JsonElementSerializer());
}
private static void RegisterClassMaps()
{
BsonClassMap.TryRegisterClassMap(cm =>
{
cm.AutoMap(); // Automatically map other properties
cm
.MapIdProperty(b => b.BookmarkId)
.SetSerializer(new StringSerializer(BsonType.String));
});
BsonClassMap.TryRegisterClassMap(map =>
{
map.AutoMap();
map.SetIgnoreExtraElements(true); // Needed for missing ID property
});
}
private static void TryRegisterSerializerOrSkipWhenExist(Type type, IBsonSerializer serializer)
{
try
{
BsonSerializer.TryRegisterSerializer(type, serializer);
}
catch (BsonSerializationException ex)
{
}
}
private static IMongoClient CreateMongoClient(IServiceProvider sp, MongoUrl mongoUrl)
{
var options = sp.GetRequiredService>().Value;
var settings = MongoClientSettings.FromUrl(mongoUrl);
settings.ClusterConfigurator = cb => cb.Subscribe(new DiagnosticsActivityEventSubscriber());
settings.ApplicationName = GetApplicationName(settings);
settings.WriteConcern = options.WriteConcern;
settings.ReadConcern = options.ReadConcern;
settings.ReadPreference = options.ReadPreference;
settings.RetryReads = options.RetryReads;
settings.RetryWrites = options.RetryWrites;
settings.SslSettings = options.SslSettings;
return new MongoClient(settings);
}
private static IMongoDatabase CreateDatabase(IServiceProvider sp, MongoUrl mongoUrl)
{
var client = sp.GetRequiredService();
return client.GetDatabase(mongoUrl.DatabaseName);
}
private static string GetApplicationName(MongoClientSettings settings) =>
string.IsNullOrWhiteSpace(settings.ApplicationName) ? "elsa_workflows" : settings.ApplicationName;
}