DEV Community

Cover image for Automate MongoDB Database Backups with C# Console Application and Windows Task Scheduler
David Au Yeung
David Au Yeung

Posted on

Automate MongoDB Database Backups with C# Console Application and Windows Task Scheduler

Introduction

In this comprehensive guide, we'll build a robust MongoDB backup solution using C# that automatically creates database backups on a scheduled basis. Our solution combines the power of MongoDB Database Tools with Windows Task Scheduler to ensure your data is safely backed up without manual intervention.

By the end of this tutorial, you'll have a complete automated backup system that creates timestamped backups, manages retention policies, and provides detailed logging for monitoring backup operations.

Prerequisites

Before we begin, ensure you have the following:

  1. MongoDB Command Line Database Tools: Download from the official MongoDB website at https://www.mongodb.com/try/download/tools. These tools include mongodump.exe which is essential for creating database backups.

  2. MongoDB Instance: A running MongoDB server (local or remote) with databases you want to backup.

  3. Windows Environment: This solution is designed for Windows systems with Task Scheduler access.

  4. Visual Studio or C# Development Environment: For building and publishing the console application.

  5. Administrative Privileges: Required for creating scheduled tasks in Windows Task Scheduler.

Step 1: Setting Up the Project

Open your IDE and create a new Console App project targeting .NET 9.0.
Add the System.Configuration.ConfigurationManager NuGet package for handling configuration files.
Create the project structure with separate classes for better organization and maintainability.

Step 2: Configuration Management

We'll use an App.config file to store all configuration settings, making our application flexible and easy to maintain without code changes.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>

  <appSettings>
    <!-- MongoDB bin path -->
    <add key="MongoExePath" value="C:\Program Files\MongoDB\mongodb-database-tools-windows-x86_64-100.12.2\bin" />

    <!-- Backup storage path -->
    <add key="BackupPath" value="C:\MongoBackups" />

    <!-- Connection string -->
    <add key="ConnectionString" value="mongodb://localhost:27017" />

    <!-- Databases to backup (comma-separated) -->
    <add key="DatabasesToBackup" value="DemoDB" />

    <!-- Days to keep backups (older ones will be deleted) -->
    <add key="BackupRetentionDays" value="7" />
  </appSettings>
</configuration>
Enter fullscreen mode Exit fullscreen mode

The configuration file allows you to specify multiple databases for backup, set retention policies, and configure connection details without modifying the source code.

Step 3: Building the Core Backup Logic

Our Tasks class handles all backup operations including database backup execution, old backup cleanup, and comprehensive logging.

using System.Configuration;
using System.Diagnostics;
using System.Text;

namespace MongoDBBackupPOC
{
    internal class Tasks
    {
        private readonly string _mongoExePath;
        private readonly string _backupPath;
        private readonly string _connectionString;

        public Tasks()
        {
            _mongoExePath = ConfigurationManager.AppSettings["MongoExePath"];
            _backupPath = ConfigurationManager.AppSettings["BackupPath"];
            _connectionString = ConfigurationManager.AppSettings["ConnectionString"];

            if (!Directory.Exists(_mongoExePath))
                throw new DirectoryNotFoundException($"MongoDB path not found: {_mongoExePath}");

            if (!Directory.Exists(_backupPath))
                Directory.CreateDirectory(_backupPath);
        }

        public bool BackupDatabase(string databaseName)
        {
            try
            {
                string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
                string backupName = $"{databaseName}_{timestamp}";
                string backupDirectory = Path.Combine(_backupPath, backupName);
                string mongoDumpPath = Path.Combine(_mongoExePath, "mongodump.exe");

                var arguments = new StringBuilder();
                if (!string.IsNullOrEmpty(_connectionString))
                    arguments.Append($"--uri \"{_connectionString}\" ");

                arguments.Append($"--db {databaseName} ");
                arguments.Append($"--out \"{backupDirectory}\"");

                var processInfo = new ProcessStartInfo
                {
                    FileName = mongoDumpPath,
                    Arguments = arguments.ToString(),
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                };

                using (var process = Process.Start(processInfo))
                {
                    process.WaitForExit();

                    if (process.ExitCode == 0)
                    {
                        LogMessage($"SUCCESS: Backup completed for {databaseName} at {backupDirectory}");
                        return true;
                    }
                    else
                    {
                        string error = process.StandardError.ReadToEnd();
                        LogMessage($"ERROR: Backup failed for {databaseName}. Error: {error}");
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                LogMessage($"ERROR: Exception during backup of {databaseName}: {ex.Message}");
                return false;
            }
        }

        public void CleanupOldBackups(int daysToKeep = 7)
        {
            try
            {
                var directories = Directory.GetDirectories(_backupPath);
                var cutoffDate = DateTime.Now.AddDays(-daysToKeep);

                foreach (var dir in directories)
                {
                    var dirInfo = new DirectoryInfo(dir);
                    if (dirInfo.CreationTime < cutoffDate)
                    {
                        Directory.Delete(dir, true);
                        LogMessage($"Deleted old backup: {dirInfo.Name}");
                    }
                }
            }
            catch (Exception ex)
            {
                LogMessage($"ERROR: Cleanup failed: {ex.Message}");
            }
        }

        private void LogMessage(string message)
        {
            string logFile = Path.Combine(_backupPath, "backup_log.txt");
            string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}";

            try
            {
                File.AppendAllText(logFile, logEntry + Environment.NewLine);
                Console.WriteLine(logEntry);
            }
            catch
            {
                Console.WriteLine(logEntry);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The BackupDatabase method creates timestamped backups using mongodump.exe, while CleanupOldBackups automatically removes backups older than the specified retention period to manage disk space efficiently.

Step 4: Creating the Main Program Logic

Our main program orchestrates the entire backup process, handling multiple databases and providing comprehensive error handling.

using System.Configuration;

namespace MongoDBBackupPOC
{
    class Program
    {
        static int Main(string[] args)
        {
            try
            {
                var tasks = new Tasks();
                bool allSuccess = true;

                // Get databases to backup from config
                string databasesConfig = ConfigurationManager.AppSettings["DatabasesToBackup"];
                string[] databases = databasesConfig?.Split(',') ?? new string[0];

                if (databases.Length == 0)
                {
                    Console.WriteLine("ERROR: No databases configured for backup");
                    return 1;
                }

                // Backup each database
                foreach (string db in databases)
                {
                    string dbName = db.Trim();
                    if (!string.IsNullOrEmpty(dbName))
                    {
                        Console.WriteLine($"Backing up database: {dbName}");
                        bool success = tasks.BackupDatabase(dbName);
                        if (!success)
                            allSuccess = false;
                    }
                }

                // Cleanup old backups
                int retentionDays = 7;
                if (int.TryParse(ConfigurationManager.AppSettings["BackupRetentionDays"], out int configDays))
                    retentionDays = configDays;

                Console.WriteLine("Cleaning up old backups...");
                tasks.CleanupOldBackups(retentionDays);

                if (allSuccess)
                {
                    Console.WriteLine("All backup operations completed successfully");
                    return 0;
                }
                else
                {
                    Console.WriteLine("Some backup operations failed");
                    return 1;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"FATAL ERROR: {ex.Message}");
                return 1;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The program returns appropriate exit codes that Windows Task Scheduler can use to determine if the backup operation succeeded or failed, enabling proper monitoring and alerting.

Step 5: Publishing and Deploying the Application

Build your application in Release mode and publish it to create a self-contained executable. This ensures the application can run on the target server without requiring the .NET runtime to be separately installed.

Use the following command or Visual Studio's publish feature to create a deployment-ready version:

dotnet publish -c Release -r win-x64 --self-contained

Copy the published files to your target server location, ensuring the MongoDB Database Tools are also installed and accessible at the configured path.

Step 6: Setting Up Windows Task Scheduler

Open Windows Task Scheduler and create a new task with the following configuration:

General Tab: Set the task name to "Daily_Backup_MongoDB" and you may configure it to run whether the user is logged on or not. Ensure it runs with highest privileges if your MongoDB instance requires elevated permissions.

Image description

Triggers Tab: Create a daily trigger set to run at 00:00:00 (midnight) or your preferred backup time. Configure it to repeat if necessary and set appropriate start and expiration dates.

Image description

Actions Tab: Create a new action with the program path pointing to your published executable: C:\Users\User\source\repos\MongoDBBackupPOC\MongoDBBackupPOC\bin\Release\net9.0\publish\MongoDBBackupPOC.exe

Image description

Conditions and Settings: Configure power management settings and failure handling according to your environment requirements.

Step 7: Testing and Monitoring

Test your backup solution by running the scheduled task manually to ensure it executes correctly. Monitor the backup log file for any errors or issues that may arise during automated execution.

Image description(Click "Run" on the right hand side to test)

Verify that backups are created with proper timestamps and that old backups are cleaned up according to your retention policy. The log file provides comprehensive information about each backup operation's success or failure.

Image description

Challenge for You!

Extend this backup solution by implementing a MongoDB Database Restore Functionality. Create a new method in the Tasks class called RestoreDatabase that:

  • Uses mongorestore.exe to restore databases from backup files
  • Provides options to restore to a different database name
  • Includes validation to ensure the backup exists before attempting restore
  • Implements proper error handling and logging for restore operations
  • Allows restoration from specific backup timestamps

Conclusion

You've successfully created a comprehensive MongoDB backup automation solution that combines C# console application development with Windows Task Scheduler. This robust system ensures your MongoDB databases are regularly backed up, properly managed, and easily monitored through detailed logging.

The solution demonstrates best practices for enterprise backup scenarios, including configurable retention policies, comprehensive error handling, and automated cleanup processes. With this foundation, you can extend the system to include features like email notifications, database restoration capabilities, and integration with monitoring systems.

Reference

MongoDB Database Tools Documentation
Windows Task Scheduler Guide

Top comments (0)