Skip to content

Commit

Permalink
feat: add mongodb container and connection support
Browse files Browse the repository at this point in the history
  • Loading branch information
ailtonguitar committed Nov 22, 2023
1 parent 69937e2 commit c43b591
Show file tree
Hide file tree
Showing 14 changed files with 476 additions and 1 deletion.
14 changes: 14 additions & 0 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<PackageVersion Include="JsonSchema.Net" Version="5.3.1" />
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components" Version="4.0.0" />
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="4.0.0" />
<PackageVersion Include="MongoDB.Driver" Version="2.22.0" />
<PackageVersion Include="MySqlConnector.DependencyInjection" Version="2.3.1" />
<PackageVersion Include="Npgsql.DependencyInjection" Version="8.0.0-rc.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0-rc.2" />
Expand Down Expand Up @@ -99,4 +100,4 @@
<PackageVersion Include="Microsoft.Signed.Wix" Version="1.0.0-v3.14.0.5722" />
<PackageVersion Include="Microsoft.DotNet.Build.Tasks.Installers" Version="8.0.0-beta.23564.4" />
</ItemGroup>
</Project>
</Project>
4 changes: 4 additions & 0 deletions samples/eShopLite/AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using Aspire.Hosting.MongoDb;

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureProvisioning();

var catalogDb = builder.AddPostgresContainer("postgres").AddDatabase("catalogdb");

builder.AddMongoDbContainer("mongodb").AddDatabase("catalogdb");

var basketCache = builder.AddRedisContainer("basketcache");

var catalogService = builder.AddProject<Projects.CatalogService>("catalogservice")
Expand Down
11 changes: 11 additions & 0 deletions src/Aspire.Hosting/MongoDB/IMongoDbResource.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Represents a MongoDb resource that requires a connection string.
/// </summary>
public interface IMongoDbResource : IResourceWithConnectionString
{
}
92 changes: 92 additions & 0 deletions src/Aspire.Hosting/MongoDB/MongoDbBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Provides extension methods for adding MongoDB resources to an <see cref="IDistributedApplicationBuilder"/>.
/// </summary>
public static class MongoDbBuilderExtensions
{
private const int DefaultContainerPort = 27017;
private const string DefaultPassword = "password";
private const string PasswordEnvVarName = "MONGO_INITDB_ROOT_PASSWORD";

/// <summary>
/// Adds a MongoDB container to the application model. The default image is "mongo" and the tag is "latest".
/// </summary>
/// <returns></returns>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="port">The host port for MongoDB.</param>
/// <param name="password">The password for the MongoDB root user. Defaults to a 'password' password.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{MongoDbContainerResource}"/>.</returns>
public static IResourceBuilder<MongoDbContainerResource> 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);
}

/// <summary>
/// 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.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="connectionString">The MongoDB connection string (optional).</param>
/// <returns>A reference to the <see cref="IResourceBuilder{MongoDbConnectionResource}"/>.</returns>
public static IResourceBuilder<MongoDbConnectionResource> 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)));
}

/// <summary>
/// Adds a MongoDB database to the application model.
/// </summary>
/// <param name="builder">The MongoDB server resource builder.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{MongoDbDatabaseResource}"/>.</returns>
public static IResourceBuilder<MongoDbDatabaseResource> AddDatabase(this IResourceBuilder<MongoDbContainerResource> 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);
}
}
20 changes: 20 additions & 0 deletions src/Aspire.Hosting/MongoDB/MongoDbConnectionResource.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// A resource that represents a MongoDb connection.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="connectionString">The MongoDb connection string.</param>
public class MongoDbConnectionResource(string name, string? connectionString) : Resource(name), IMySqlResource
{
private readonly string? _connectionString = connectionString;

/// <summary>
/// Gets the connection string for the MongoDb server.
/// </summary>
/// <returns>The specified connection string.</returns>
public string? GetConnectionString() => _connectionString;
}
30 changes: 30 additions & 0 deletions src/Aspire.Hosting/MongoDB/MongoDbContainerResource.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// A resource that represents a MongoDb container.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="password">The MongoDb root password.</param>
public class MongoDbContainerResource(string name, string password) : ContainerResource(name), IMongoDbResource
{
public string Password { get; } = password;

/// <summary>
/// Gets the connection string for the MongoDb server.
/// </summary>
/// <returns>A connection string for the MongoDb server in the form "mongodb://host:port".</returns>
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}";
}
}
29 changes: 29 additions & 0 deletions src/Aspire.Hosting/MongoDB/MongoDbDatabaseResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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;

/// <summary>
/// A resource that represents a MongoDb database. This is a child resource of a <see cref="MongoDbContainerResource"/>.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="mongoDbContainer">The MongoDb server resource associated with this database.</param>
public class MongoDbDatabaseResource(string name, MongoDbContainerResource mongoDbContainer)
: Resource(name), IMongoDbResource, IResourceWithParent<MongoDbContainerResource>
{
public MongoDbContainerResource Parent => mongoDbContainer;

/// <summary>
/// Gets the connection string for the MongoDb database.
/// </summary>
/// <returns>A connection string for the MongoDb database.</returns>
public string? GetConnectionString()
{
if (Parent.GetConnectionString() is { } connectionString)
{
return $"{connectionString}/{Name}";
}

throw new DistributedApplicationException("Parent resource connection string was null.");
}
}
17 changes: 17 additions & 0 deletions src/Components/Aspire.MongoDB.Driver/Aspire.MongoDB.Driver.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(NetCurrent)</TargetFramework>
<IsPackable>true</IsPackable>
<PackageTags>$(ComponentDatabasePackageTags) MongoDb</PackageTags>
<Description>A generic MongoDb client that integrates with Aspire.</Description>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
</ItemGroup>

</Project>

0 comments on commit c43b591

Please sign in to comment.