Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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