Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
Hosting.Azure.Dapr.Redis.Tests,
Hosting.Azure.Dapr.Tests,
Hosting.Azure.DataApiBuilder.Tests,
Hosting.Azure.Extensions.Tests,
Hosting.Bun.Tests,
Hosting.Dapr.Tests,
Hosting.DbGate.Tests,
Expand Down
5 changes: 5 additions & 0 deletions CommunityToolkit.Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<Folder Name="/examples/adminer/">
<Project Path="examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.csproj" />
</Folder>
<Folder Name="/examples/azure-ext/">
<Project Path="examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost/CommunityToolkit.Aspire.Azure.Extensions.AppHost.csproj" />
</Folder>
<Folder Name="/examples/bun/">
<Project Path="examples/bun/CommunityToolkit.Aspire.Hosting.Bun.AppHost/CommunityToolkit.Aspire.Hosting.Bun.AppHost.csproj" />
</Folder>
Expand Down Expand Up @@ -184,6 +187,7 @@
<Project Path="src/CommunityToolkit.Aspire.Hosting.ActiveMQ/CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Adminer/CommunityToolkit.Aspire.Hosting.Adminer.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Azure.Extensions/CommunityToolkit.Aspire.Hosting.Azure.Extensions.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Bun/CommunityToolkit.Aspire.Hosting.Bun.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.DbGate/CommunityToolkit.Aspire.Hosting.DbGate.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Deno/CommunityToolkit.Aspire.Hosting.Deno.csproj" />
Expand Down Expand Up @@ -242,6 +246,7 @@
<Project Path="tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests/CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Bun.Tests/CommunityToolkit.Aspire.Hosting.Bun.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Deno.Tests/CommunityToolkit.Aspire.Hosting.Deno.Tests.csproj" />
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ This repository contains the source code for the Aspire Community Toolkit, a col
| - **Learn More**: [`Hosting.SurrealDb`][surrealdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.SurrealDb][surrealdb-shields]][surrealdb-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.SurrealDb][surrealdb-shields-preview]][surrealdb-nuget-preview] | An Aspire hosting integration leveraging the [SurrealDB](https://surrealdb.com/) container. |
| - **Learn More**: [`SurrealDb`][surrealdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.SurrealDb][surrealdb-client-shields]][surrealdb-client-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.SurrealDb][surrealdb-client-shields-preview]][surrealdb-client-nuget-preview] | An Aspire client integration for the [SurrealDB](https://github.com/surrealdb/surrealdb.net/) package. |
| - **Learn More**: [`Hosting.Elasticsearch.Extensions`][elasticsearch-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions][elasticsearch-ext-shields]][elasticsearch-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions][elasticsearch-ext-shields-preview]][elasticsearch-ext-nuget-preview] | An integration that contains some additional extensions for hosting Elasticsearch container. |
| - **Learn More**: [`Hosting.Azure.Extensions`][azure-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Azure.Extensions][azure-ext-shields]][azure-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Azure.Extensions][azure-ext-shields-preview]][azure-ext-nuget-preview] | An integration that contains some additional extensions for hosting Azure container. |

## 🙌 Getting Started

Expand Down Expand Up @@ -280,3 +281,8 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
[elasticsearch-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions/
[elasticsearch-ext-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions?label=nuget%20(preview)
[elasticsearch-ext-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions/absoluteLatest
[azure-ext-integration-docs]: https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-azure-extensions
[azure-ext-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Azure.Extensions
[azure-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Azure.Extensions/
[azure-ext-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Azure.Extensions?label=nuget%20(preview)
[azure-ext-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Azure.Extensions/absoluteLatest
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Aspire.AppHost.Sdk/13.1.0">

<PropertyGroup>
<OutputType>Exe</OutputType>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.Azure.Storage" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Azure.Extensions\CommunityToolkit.Aspire.Hosting.Azure.Extensions.csproj" IsAspireProjectResource="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var builder = DistributedApplication.CreateBuilder(args);

var storage = builder.AddAzureStorage("azure-storage")
.RunAsEmulator(azurite =>
{
azurite
.WithArgs("--disableProductStyleUrl")
.WithBlobPort(27000)
.WithQueuePort(27001)
.WithTablePort(27002)
.WithDataVolume("storage");
});

var blobs = storage.AddBlobs("blobs").WithAzureStorageExplorer();

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17160;http://localhost:15192",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21259",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:23002",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22192"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15192",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19033",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18007",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20079"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;

namespace Aspire.Hosting;

/// <summary>
/// Provides extension methods for adding Azure Storage Explorer resources to the application model.
/// </summary>
public static class AzureBlobStorageResourceBuilderExtensions
{
/// <summary>
/// Adds an Azure Storage Explorer instance to a Blob storage resource.
/// </summary>
/// <param name="blobs">The builder for the <see cref="AzureBlobStorageResource"/>.</param>
/// <param name="configureContainer">Configuration callback for Azure Storage Explorer container resource.</param>
/// <param name="name">The name of the resource.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
/// <remarks>
/// <example>
/// Add an Azure Storage Explorer container to the application model and reference it in a .NET project.
/// <code lang="csharp">
/// var builder = DistributedApplication.CreateBuilder(args);
///
/// var storage = builder.AddAzureStorage("storage")
/// .RunAsEmulator(azurite =>
/// {
/// azurite
/// .WithBlobPort(27000)
/// .WithQueuePort(27001)
/// .WithTablePort(27002);
/// });
/// var blobs = storage.AddBlobs("blobs")
/// .WithAzureStorageExplorer();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<AzureBlobStorageResource> WithAzureStorageExplorer(
this IResourceBuilder<AzureBlobStorageResource> blobs,
Action<IResourceBuilder<AzureStorageExplorerResource>>? configureContainer = null,
[ResourceName] string? name = null
)
{
string resourceNname = name ?? $"{blobs.Resource.Name}-explorer";
var builder = blobs.ApplicationBuilder
.AddAzureStorageExplorer(resourceNname)
.WithStorageResource(blobs)
.WithParentRelationship(blobs);

if (blobs.Resource.Parent.IsEmulator)
{
builder.WithAzurite();
}

configureContainer?.Invoke(builder);

return blobs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;

namespace Aspire.Hosting;

/// <summary>
/// Provides extension methods for adding Azure Storage Explorer resources to the application model.
/// </summary>
public static class AzureQueueStorageResourceBuilderExtensions
{
/// <summary>
/// Adds an Azure Storage Explorer instance to a Queue storage resource.
/// </summary>
/// <param name="queues">The builder for the <see cref="AzureQueueStorageResource"/>.</param>
/// <param name="configureContainer">Configuration callback for Azure Storage Explorer container resource.</param>
/// <param name="name">The name of the resource.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
/// <remarks>
/// <example>
/// Add an Azure Storage Explorer container to the application model and reference it in a .NET project.
/// <code lang="csharp">
/// var builder = DistributedApplication.CreateBuilder(args);
///
/// var storage = builder.AddAzureStorage("storage")
/// .RunAsEmulator(azurite =>
/// {
/// azurite
/// .WithBlobPort(27000)
/// .WithQueuePort(27001)
/// .WithTablePort(27002);
/// });
/// var queues = storage.AddQueues("queues")
/// .WithAzureStorageExplorer();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// </remarks>
public static IResourceBuilder<AzureQueueStorageResource> WithAzureStorageExplorer(
this IResourceBuilder<AzureQueueStorageResource> queues,
Action<IResourceBuilder<AzureStorageExplorerResource>>? configureContainer = null,
[ResourceName] string? name = null
)
{
string resourceNname = name ?? $"{queues.Resource.Name}-explorer";
var builder = queues.ApplicationBuilder
.AddAzureStorageExplorer(resourceNname)
.WithStorageResource(queues)
.WithParentRelationship(queues);

if (queues.Resource.Parent.IsEmulator)
{
builder.WithAzurite();
}

configureContainer?.Invoke(builder);

return queues;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting;

/// <summary>
/// Provides extension methods for adding Azure Storage Explorer resources to the application model.
/// </summary>
public static class AzureStorageExplorerBuilderExtensions
{
private const int AzureStorageExplorerPort = 8080;

/// <summary>
/// Configures the host port that the Azure Storage Explorer resource is exposed on instead of using randomly assigned port.
/// </summary>
/// <param name="builder">The resource builder for Azure Storage Explorer.</param>
/// <param name="port">The port to bind on the host. If <see langword="null"/> is used random port will be assigned.</param>
/// <returns>The resource builder for Azure Storage Explorer.</returns>
public static IResourceBuilder<AzureStorageExplorerResource> WithHostPort(this IResourceBuilder<AzureStorageExplorerResource> builder, int? port)
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithEndpoint(AzureStorageExplorerResource.PrimaryEndpointName, endpoint =>
{
endpoint.Port = port;
});
}

/// <summary>
/// Adds an Azure Storage Explorer resource to the application model.
/// The default image is <inheritdoc cref="AzureStorageExplorerContainerImageTags.Image"/> and the tag is <inheritdoc cref="AzureStorageExplorerContainerImageTags.Tag"/>.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource.</param>
/// <param name="port">The host port for the Azure Storage Explorer instance.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
internal static IResourceBuilder<AzureStorageExplorerResource> AddAzureStorageExplorer(
this IDistributedApplicationBuilder builder,
[ResourceName] string name,
int? port = null
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(name);

var explorer = new AzureStorageExplorerResource(name);

return builder.AddResource(explorer)
.WithHttpEndpoint(
port: port,
targetPort: AzureStorageExplorerPort,
name: AzureStorageExplorerResource.PrimaryEndpointName
)
.WithImage(AzureStorageExplorerContainerImageTags.Image, AzureStorageExplorerContainerImageTags.Tag)
.WithImageRegistry(AzureStorageExplorerContainerImageTags.Registry)
.ExcludeFromManifest();
}

/// <summary>
/// Allows Azure Storage Explorer to work with the Azure Emulator (Azurite).
/// </summary>
/// <param name="builder">The builder for the <see cref="AzureStorageExplorerResource"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
internal static IResourceBuilder<AzureStorageExplorerResource> WithAzurite(
this IResourceBuilder<AzureStorageExplorerResource> builder
)
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithEnvironment("AZURITE", "true");
}

internal static IResourceBuilder<AzureStorageExplorerResource> WithStorageResource(
this IResourceBuilder<AzureStorageExplorerResource> builder,
IResourceBuilder<IResourceWithConnectionString> resourceBuilder
)
{
ArgumentNullException.ThrowIfNull(builder);

return builder
.WaitFor(resourceBuilder)
.WithEnvironment(e =>
{
e.EnvironmentVariables["AZURE_STORAGE_CONNECTIONSTRING"] =
new ConnectionStringReference(resourceBuilder.Resource, optional: false);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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;

internal sealed class AzureStorageExplorerContainerImageTags
{
/// <summary>docker.io</summary>
public const string Registry = "docker.io";
/// <summary>sebagomez/azurestorageexplorer</summary>
public const string Image = "sebagomez/azurestorageexplorer";
/// <summary>3.1.0</summary>
public const string Tag = "3.1.0";
}
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 an Azure Storage Explorer container.
/// </summary>
/// <param name="name">The name of the resource.</param>
public class AzureStorageExplorerResource([ResourceName] string name) : ContainerResource(name)
{
internal const string PrimaryEndpointName = "http";

private EndpointReference? _primaryEndpoint;

/// <summary>
/// Gets the primary endpoint for the Azure Storage Explorer instance.
/// </summary>
public EndpointReference PrimaryEndpoint => _primaryEndpoint ??= new(this, PrimaryEndpointName);

/// <summary>
/// Gets the host endpoint reference for this resource.
/// </summary>
public EndpointReferenceExpression Host => PrimaryEndpoint.Property(EndpointProperty.Host);

/// <summary>
/// Gets the port endpoint reference for this resource.
/// </summary>
public EndpointReferenceExpression Port => PrimaryEndpoint.Property(EndpointProperty.Port);
}
Loading
Loading