diff --git a/Aspire.sln b/Aspire.sln
index d09f21713aa..713b364cb5c 100644
--- a/Aspire.sln
+++ b/Aspire.sln
@@ -158,6 +158,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.MySqlConnector.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject.IntegrationServiceA", "tests\testproject\TestProject.IntegrationServiceA\TestProject.IntegrationServiceA.csproj", "{DCF2D47A-921A-4900-B5B2-CF97B3531CE8}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.MongoDB.Driver", "src\Components\Aspire.MongoDB.Driver\Aspire.MongoDB.Driver.csproj", "{20A5A907-A135-4735-B4BF-E13514F360E3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.MongoDB.Driver.Tests", "tests\Aspire.MongoDB.Driver.Tests\Aspire.MongoDB.Driver.Tests.csproj", "{E592E447-BA3C-44FA-86C1-EBEDC864A644}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -424,6 +428,14 @@ Global
{DCF2D47A-921A-4900-B5B2-CF97B3531CE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DCF2D47A-921A-4900-B5B2-CF97B3531CE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DCF2D47A-921A-4900-B5B2-CF97B3531CE8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20A5A907-A135-4735-B4BF-E13514F360E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20A5A907-A135-4735-B4BF-E13514F360E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20A5A907-A135-4735-B4BF-E13514F360E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20A5A907-A135-4735-B4BF-E13514F360E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E592E447-BA3C-44FA-86C1-EBEDC864A644}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E592E447-BA3C-44FA-86C1-EBEDC864A644}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E592E447-BA3C-44FA-86C1-EBEDC864A644}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E592E447-BA3C-44FA-86C1-EBEDC864A644}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -497,6 +509,8 @@ Global
{165411FE-755E-4869-A756-F87F455860AC} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{CA283D7F-EB95-4353-B196-C409965D2B42} = {27381127-6C45-4B4C-8F18-41FF48DFE4B2}
{C8079F06-304F-49B1-A0C1-45AA3782A923} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
+ {20A5A907-A135-4735-B4BF-E13514F360E3} = {27381127-6C45-4B4C-8F18-41FF48DFE4B2}
+ {E592E447-BA3C-44FA-86C1-EBEDC864A644} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{DCF2D47A-921A-4900-B5B2-CF97B3531CE8} = {975F6F41-B455-451D-A312-098DE4A167B6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6827245d7eb..c52d7ad0173 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -71,6 +71,7 @@
+
@@ -99,4 +100,4 @@
-
+
\ No newline at end of file
diff --git a/src/Aspire.Hosting/MongoDB/IMongoDbResource.cs b/src/Aspire.Hosting/MongoDB/IMongoDbResource.cs
new file mode 100644
index 00000000000..2c149774a1a
--- /dev/null
+++ b/src/Aspire.Hosting/MongoDB/IMongoDbResource.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// Represents a MongoDb resource that requires a connection string.
+///
+public interface IMongoDbResource : IResourceWithConnectionString
+{
+}
diff --git a/src/Aspire.Hosting/MongoDB/MongoDbBuilderExtensions.cs b/src/Aspire.Hosting/MongoDB/MongoDbBuilderExtensions.cs
new file mode 100644
index 00000000000..ae0521d99f9
--- /dev/null
+++ b/src/Aspire.Hosting/MongoDB/MongoDbBuilderExtensions.cs
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Net.Sockets;
+using System.Text.Json;
+using Aspire.Hosting.ApplicationModel;
+
+namespace Aspire.Hosting.MongoDb;
+
+///
+/// Provides extension methods for adding MongoDB resources to an .
+///
+public static class MongoDbBuilderExtensions
+{
+ private const int DefaultContainerPort = 27017;
+ private const string DefaultPassword = "password";
+ private const string PasswordEnvVarName = "MONGO_INITDB_ROOT_PASSWORD";
+
+ ///
+ /// Adds a MongoDB container to the application model. The default image is "mongo" and the tag is "latest".
+ ///
+ ///
+ /// The .
+ /// The name of the resource. This name will be used as the connection string name when referenced in a dependency.
+ /// The host port for MongoDB.
+ /// The password for the MongoDB root user. Defaults to a 'password' password.
+ /// A reference to the .
+ public static IResourceBuilder AddMongoDbContainer(
+ this IDistributedApplicationBuilder builder,
+ string name,
+ int port = DefaultContainerPort,
+ string password = DefaultPassword)
+ {
+ var mongoDbContainer = new MongoDbContainerResource(name, password);
+
+ return builder
+ .AddResource(mongoDbContainer)
+ .WithAnnotation(new ManifestPublishingCallbackAnnotation(WriteMongoDbContainerToManifest))
+ .WithAnnotation(new ServiceBindingAnnotation(ProtocolType.Tcp, port: port, containerPort: DefaultContainerPort)) // Internal port is always 27017.
+ .WithAnnotation(new ContainerImageAnnotation { Image = "mongo", Tag = "latest" })
+ .WithEnvironment(PasswordEnvVarName, () => mongoDbContainer.Password);
+ }
+
+ ///
+ /// Adds a MongoDB connection to the application model. Connection strings can also be read from the connection string section of the configuration using the name of the resource.
+ ///
+ /// The .
+ /// The name of the resource. This name will be used as the connection string name when referenced in a dependency.
+ /// The MongoDB connection string (optional).
+ /// A reference to the .
+ public static IResourceBuilder AddMongoDbConnection(this IDistributedApplicationBuilder builder, string name, string? connectionString = null)
+ {
+ var mongoDbConnection = new MongoDbConnectionResource(name, connectionString);
+
+ return builder
+ .AddResource(mongoDbConnection)
+ .WithAnnotation(new ManifestPublishingCallbackAnnotation((json) => WriteMongoDbConnectionToManifest(json, mongoDbConnection)));
+ }
+
+ ///
+ /// Adds a MongoDB database to the application model.
+ ///
+ /// The MongoDB server resource builder.
+ /// The name of the resource. This name will be used as the connection string name when referenced in a dependency.
+ /// A reference to the .
+ public static IResourceBuilder AddDatabase(this IResourceBuilder builder, string name)
+ {
+ var mongoDbDatabase = new MongoDbDatabaseResource(name, builder.Resource);
+
+ return builder.ApplicationBuilder
+ .AddResource(mongoDbDatabase)
+ .WithAnnotation(new ManifestPublishingCallbackAnnotation(
+ (json) => WriteMongoDbDatabaseToManifest(json, mongoDbDatabase)));
+ }
+
+ private static void WriteMongoDbContainerToManifest(Utf8JsonWriter jsonWriter)
+ {
+ jsonWriter.WriteString("type", "mongodb.server.v0");
+ }
+
+ private static void WriteMongoDbConnectionToManifest(Utf8JsonWriter jsonWriter, MongoDbConnectionResource mongoDbConnection)
+ {
+ jsonWriter.WriteString("type", "mongodb.connection.v0");
+ jsonWriter.WriteString("connectionString", mongoDbConnection.GetConnectionString());
+ }
+
+ private static void WriteMongoDbDatabaseToManifest(Utf8JsonWriter json, MongoDbDatabaseResource mongoDbDatabase)
+ {
+ json.WriteString("type", "mongodb.database.v0");
+ json.WriteString("parent", mongoDbDatabase.Parent.Name);
+ }
+}
diff --git a/src/Aspire.Hosting/MongoDB/MongoDbConnectionResource.cs b/src/Aspire.Hosting/MongoDB/MongoDbConnectionResource.cs
new file mode 100644
index 00000000000..f2b15b94205
--- /dev/null
+++ b/src/Aspire.Hosting/MongoDB/MongoDbConnectionResource.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// A resource that represents a MongoDb connection.
+///
+/// The name of the resource.
+/// The MongoDb connection string.
+public class MongoDbConnectionResource(string name, string? connectionString) : Resource(name), IMySqlResource
+{
+ private readonly string? _connectionString = connectionString;
+
+ ///
+ /// Gets the connection string for the MongoDb server.
+ ///
+ /// The specified connection string.
+ public string? GetConnectionString() => _connectionString;
+}
diff --git a/src/Aspire.Hosting/MongoDB/MongoDbContainerResource.cs b/src/Aspire.Hosting/MongoDB/MongoDbContainerResource.cs
new file mode 100644
index 00000000000..322b5517665
--- /dev/null
+++ b/src/Aspire.Hosting/MongoDB/MongoDbContainerResource.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// A resource that represents a MongoDb container.
+///
+/// The name of the resource.
+/// The MongoDb root password.
+public class MongoDbContainerResource(string name, string password) : ContainerResource(name), IMongoDbResource
+{
+ public string Password { get; } = password;
+
+ ///
+ /// Gets the connection string for the MongoDb server.
+ ///
+ /// A connection string for the MongoDb server in the form "mongodb://host:port".
+ public string? GetConnectionString()
+ {
+ if (!this.TryGetAllocatedEndPoints(out var allocatedEndpoints))
+ {
+ throw new DistributedApplicationException("Expected allocated endpoints!");
+ }
+
+ var allocatedEndpoint = allocatedEndpoints.Single();
+
+ return $"mongodb://root:{Password}@{allocatedEndpoint.Address}:{allocatedEndpoint.Port}";
+ }
+}
diff --git a/src/Aspire.Hosting/MongoDB/MongoDbDatabaseResource.cs b/src/Aspire.Hosting/MongoDB/MongoDbDatabaseResource.cs
new file mode 100644
index 00000000000..9a9b0916a5d
--- /dev/null
+++ b/src/Aspire.Hosting/MongoDB/MongoDbDatabaseResource.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// A resource that represents a MongoDb database. This is a child resource of a .
+///
+/// The name of the resource.
+/// The MongoDb server resource associated with this database.
+public class MongoDbDatabaseResource(string name, MongoDbContainerResource mongoDbContainer)
+ : Resource(name), IMongoDbResource, IResourceWithParent
+{
+ public MongoDbContainerResource Parent => mongoDbContainer;
+
+ ///
+ /// Gets the connection string for the MongoDb database.
+ ///
+ /// A connection string for the MongoDb database.
+ public string? GetConnectionString()
+ {
+ if (Parent.GetConnectionString() is { } connectionString)
+ {
+ return $"{connectionString}/{Name}";
+ }
+ else
+ {
+ throw new DistributedApplicationException("Parent resource connection string was null.");
+ }
+ }
+}
diff --git a/src/Components/Aspire.MongoDB.Driver/Aspire.MongoDB.Driver.csproj b/src/Components/Aspire.MongoDB.Driver/Aspire.MongoDB.Driver.csproj
new file mode 100644
index 00000000000..c3968ef7c43
--- /dev/null
+++ b/src/Components/Aspire.MongoDB.Driver/Aspire.MongoDB.Driver.csproj
@@ -0,0 +1,17 @@
+
+
+
+ $(NetCurrent)
+ true
+ $(ComponentDatabasePackageTags) MongoDb
+ A generic MongoDb client that integrates with Aspire.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Components/Aspire.MongoDB.Driver/AspireMongoDbDriverExtensions.cs b/src/Components/Aspire.MongoDB.Driver/AspireMongoDbDriverExtensions.cs
new file mode 100644
index 00000000000..31ca81422e9
--- /dev/null
+++ b/src/Components/Aspire.MongoDB.Driver/AspireMongoDbDriverExtensions.cs
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Aspire.MongoDB.Driver;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using MongoDB.Driver;
+
+namespace Microsoft.Extensions.Hosting;
+
+///
+/// Extension methods for connecting MongoDB database with MongoDB.Driver client.
+///
+public static class AspireMongoDbDriverExtensions
+{
+ private const string DefaultConfigSectionName = "Aspire:MongoDB";
+
+ ///
+ /// Registers instance for connecting MongoDB database with MongoDB.Driver client.
+ ///
+ /// The to read config from and add services to.
+ /// A name used to retrieve the connection string from the ConnectionStrings configuration section.
+ /// An optional delegate that can be used for customizing options. It's invoked after the settings are read from the configuration.
+ /// Reads the configuration from "Aspire:MongoDB" section.
+ /// Thrown when mandatory is not provided.
+ public static void AddMongoDbDataSource(
+ this IHostApplicationBuilder builder,
+ string connectionName,
+ Action? configureSettings = null)
+ => AddMongoDbDataSource(builder, DefaultConfigSectionName, configureSettings, connectionName, serviceKey: null);
+
+ ///
+ /// Registers instance for connecting MongoDB database with MongoDB.Driver client.
+ ///
+ /// The to read config from and add services to.
+ /// The name of the component, which is used as the of the service and also to retrieve the connection string from the ConnectionStrings configuration section.
+ /// An optional delegate that can be used for customizing options. It's invoked after the settings are read from the configuration.
+ /// Reads the configuration from "Aspire:MongoDB:{name}" section.
+ /// Thrown if mandatory is null.
+ /// Thrown when mandatory is not provided.
+ public static void AddKeyedMongoDbDataSource(
+ this IHostApplicationBuilder builder,
+ string name,
+ Action? configureSettings = null)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(name);
+
+ AddMongoDbDataSource(builder, $"{DefaultConfigSectionName}:{name}", configureSettings, connectionName: name, serviceKey: name);
+ }
+
+ private static void AddMongoDbDataSource(
+ IHostApplicationBuilder builder,
+ string configurationSectionName,
+ Action? configureSettings,
+ string connectionName,
+ object? serviceKey)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ var settings = builder.GetMongoDbSettings(
+ configurationSectionName,
+ configureSettings,
+ connectionName);
+
+ settings.ValidateSettings(connectionName, configurationSectionName);
+
+ builder.RegisterMongoDbServices(settings, serviceKey);
+ }
+
+ private static void RegisterMongoDbServices(this IHostApplicationBuilder builder, MongoDbSettings settings, object? serviceKey)
+ {
+ if (serviceKey is null)
+ {
+ builder.Services
+ .AddSingleton(_ => new MongoClient(settings.ConnectionString));
+ return;
+ }
+
+ builder.Services.AddKeyedSingleton(
+ serviceKey,
+ (_, __) => new MongoClient(settings.ConnectionString));
+ }
+
+ private static MongoDbSettings GetMongoDbSettings(this IHostApplicationBuilder builder, string configurationSectionName, Action? configureSettings, string connectionName)
+ {
+ MongoDbSettings settings = new();
+
+ builder.Configuration
+ .GetSection(configurationSectionName)
+ .Bind(settings);
+
+ if (builder.Configuration.GetConnectionString(connectionName) is string connectionString)
+ {
+ settings.ConnectionString = connectionString;
+ }
+
+ configureSettings?.Invoke(settings);
+
+ return settings;
+ }
+
+ private static void ValidateSettings(this MongoDbSettings settings, string connectionName, string configurationSectionName)
+ {
+ if (string.IsNullOrEmpty(settings.ConnectionString))
+ {
+ throw new InvalidOperationException($"ConnectionString is missing. It should be provided in 'ConnectionStrings:{connectionName}' or under the 'ConnectionString' key in '{configurationSectionName}' configuration section.");
+ }
+ }
+}
diff --git a/src/Components/Aspire.MongoDB.Driver/ConfigurationSchema.json b/src/Components/Aspire.MongoDB.Driver/ConfigurationSchema.json
new file mode 100644
index 00000000000..824c57cfc6c
--- /dev/null
+++ b/src/Components/Aspire.MongoDB.Driver/ConfigurationSchema.json
@@ -0,0 +1,31 @@
+{
+ "definitions": {
+ "logLevel": {
+ "properties": {
+ "MongoDB": {
+ "$ref": "#/definitions/logLevelThreshold"
+ },
+ "MongoDB.Driver": {
+ "$ref": "#/definitions/logLevelThreshold"
+ }
+ }
+ }
+ },
+ "properties": {
+ "Aspire": {
+ "type": "object",
+ "properties": {
+ "MongoDB": {
+ "type": "object",
+ "properties": {
+ "ConnectionString": {
+ "type": "string",
+ "description": "Gets or sets the connection string of the MongoDB database to connect to."
+ }
+ }
+ }
+ }
+ }
+ },
+ "type": "object"
+}
diff --git a/src/Components/Aspire.MongoDB.Driver/MongoDbSettings.cs b/src/Components/Aspire.MongoDB.Driver/MongoDbSettings.cs
new file mode 100644
index 00000000000..05b3e6efea7
--- /dev/null
+++ b/src/Components/Aspire.MongoDB.Driver/MongoDbSettings.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Aspire.MongoDB.Driver;
+
+///
+/// Provides the client configuration settings for connecting to a MongoDB database using MongoDB driver.
+///
+public class MongoDbSettings
+{
+ ///
+ /// The connection string of the MongoDB database to connect to.
+ ///
+ public string? ConnectionString { get; set; }
+}
diff --git a/tests/Aspire.MongoDB.Driver.Tests/Aspire.MongoDB.Driver.Tests.csproj b/tests/Aspire.MongoDB.Driver.Tests/Aspire.MongoDB.Driver.Tests.csproj
new file mode 100644
index 00000000000..d3129feefc8
--- /dev/null
+++ b/tests/Aspire.MongoDB.Driver.Tests/Aspire.MongoDB.Driver.Tests.csproj
@@ -0,0 +1,12 @@
+
+
+
+ $(NetCurrent)
+
+
+
+
+
+
+
+
diff --git a/tests/Aspire.MongoDB.Driver.Tests/AspireMongoDbDriverExtensionsTests.cs b/tests/Aspire.MongoDB.Driver.Tests/AspireMongoDbDriverExtensionsTests.cs
new file mode 100644
index 00000000000..08b7d1480b6
--- /dev/null
+++ b/tests/Aspire.MongoDB.Driver.Tests/AspireMongoDbDriverExtensionsTests.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using MongoDB.Driver;
+using Xunit;
+
+namespace Aspire.MongoDB.Driver.Tests;
+
+public class AspireMongoDbDriverExtensionsTests
+{
+ private const string ConnectionString = "mongodb://localhost:27017";
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void ReadsFromConnectionStringsCorrectly(bool useKeyed)
+ {
+ var builder = Host.CreateEmptyApplicationBuilder(null);
+ builder.Configuration.AddInMemoryCollection([
+ new KeyValuePair("ConnectionStrings:mongodb", ConnectionString)
+ ]);
+
+ if (useKeyed)
+ {
+ builder.AddKeyedMongoDbDataSource("mongodb");
+ }
+ else
+ {
+ builder.AddMongoDbDataSource("mongodb");
+ }
+
+ var host = builder.Build();
+ var mongoClient = useKeyed ?
+ host.Services.GetRequiredKeyedService("mongodb") :
+ host.Services.GetRequiredService();
+
+ var uri = MongoUrl.Create(ConnectionString);
+
+ Assert.Equal(uri.Server.Host, mongoClient.Settings.Server.Host);
+ Assert.Equal(uri.Server.Port, mongoClient.Settings.Server.Port);
+ }
+}