using System.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Core.Events; namespace ExpenseTracker.Persistence.MongoDb; public class MongoDbContext : IDisposable { private IMongoDatabase Database { get; set; } private MongoClient Client { get; set; } public IClientSessionHandle Session { get; private set; } private readonly List> _commands; public MongoDbContext(IConfiguration configuration, ILogger logger) { var settings = new MongoClientSettings(); settings.ClusterConfigurator = cb => { cb.Subscribe(e => { logger.LogDebug( "{@DateUtc} {@TimeUtc} {@TraceId} {@SpanId} Starting performing MongoDB command {@CommandName}.\nQuery: {@Query}.", DateTime.UtcNow.ToString("yyyy-MM-dd"), DateTime.UtcNow.ToString("HH:mm:ss.FFF"), Activity.Current?.TraceId.ToString(), Activity.Current?.SpanId.ToString(), e.CommandName, e.Command.ToString()); }); cb.Subscribe(e => { logger.LogCritical( "{@DateUtc} {@TimeUtc} {@TraceId} {@SpanId} MongoDB command {@CommandName} failed with exception {@Exception}.", DateTime.UtcNow.ToString("yyyy-MM-dd"), DateTime.UtcNow.ToString("HH:mm:ss.FFF"), Activity.Current?.TraceId.ToString(), Activity.Current?.SpanId.ToString(), e.CommandName, e.Failure); }); cb.Subscribe(e => { logger.LogDebug( "{@DateUtc} {@TimeUtc} {@TraceId} {@SpanId} Finished performing MongoDB command {@CommandName} in {@DurationInSeconds} seconds.", DateTime.UtcNow.ToString("yyyy-MM-dd"), DateTime.UtcNow.ToString("HH:mm:ss.FFF"), Activity.Current?.TraceId.ToString(), Activity.Current?.SpanId.ToString(), e.CommandName, e.Duration.TotalSeconds); }); }; settings.Server = new MongoServerAddress(configuration["Database:ConnectionString"].Split(':')[0]); Client = new MongoClient(settings); Database = Client.GetDatabase(configuration["Database:DomainPartitionName"]); _commands = new List>(); } public async Task SaveAsync(CancellationToken cancellationToken) { // Console.WriteLine($"\n\n\n{_commands.Count}\n\n\n"); // if (_commands.Count == 1) // { // var task = _commands.First(); // await task(); // // return 1; // } using (Session = await Client.StartSessionAsync()) { Session.StartTransaction(); try { var commandTasks = _commands.Select(c => c()); await Task.WhenAll(commandTasks); } catch (Exception) { await Session.AbortTransactionAsync(cancellationToken); throw; } await Session.CommitTransactionAsync(cancellationToken); } return _commands.Count; } public IMongoCollection GetCollection(string name) { return Database.GetCollection(name); } public void AddCommand(Func command) { _commands.Add(command); } public void Dispose() { Session?.Dispose(); GC.SuppressFinalize(this); } }