Skip to content

Update to Aspire 9.4 #770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 30, 2025
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Nullable>enable</Nullable>

<AspireMajorVersion>9</AspireMajorVersion>
<AspireVersion>$(AspireMajorVersion).3.1</AspireVersion>
<AspireVersion>$(AspireMajorVersion).4.0</AspireVersion>
<AspireAppHostSdkVersion>$(AspireVersion)</AspireAppHostSdkVersion>
<AspNetCoreVersion>9.0.0</AspNetCoreVersion>
<DotNetExtensionsVersion>9.0.4</DotNetExtensionsVersion>
Expand All @@ -37,8 +37,8 @@

<!-- Versioning -->
<PropertyGroup>
<ToolkitMinorVersion>6</ToolkitMinorVersion>
<ToolkitPatchVersion>1</ToolkitPatchVersion>
<ToolkitMinorVersion>7</ToolkitMinorVersion>
<ToolkitPatchVersion>0</ToolkitPatchVersion>
<ToolkitPreviewVersion>preview.1</ToolkitPreviewVersion>

<VersionPrefix>$(AspireMajorVersion).$(ToolkitMinorVersion).$(ToolkitPatchVersion)</VersionPrefix>
Expand Down
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageVersion Include="Aspire.Hosting.Redis" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.MongoDB" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.MySql" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" />
</ItemGroup>
<ItemGroup Label="Core Packages">
<!-- AspNetCore packages -->
Expand All @@ -42,7 +42,7 @@
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="$(DotNetExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(DotNetExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(DotNetExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" />
<!-- .NET packages -->
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.4.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.1.0" />
Expand All @@ -62,7 +62,7 @@
</ItemGroup>
<ItemGroup Label="Integration Packages">
<!-- External packages -->
<PackageVersion Include="Azure.Provisioning.AppContainers" Version="1.0.0" />
<PackageVersion Include="Azure.Provisioning.AppContainers" Version="1.1.0" />
<PackageVersion Include="JsonSchema.Net" Version="7.3.4" />
<PackageVersion Include="OllamaSharp" Version="5.1.12" />
<PackageVersion Include="OpenFeature.Contrib.GOFeatureFlag" Version="0.2.1" />
Expand Down Expand Up @@ -109,7 +109,7 @@
<PackageVersion Include="Testcontainers.MsSql" Version="$(TestContainersVersion)" />
</ItemGroup>
<ItemGroup Label=".NET 9 Overrides" Condition="'$(TargetFramework)' == 'net9.0'">
<PackageVersion Update="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.4" />
<PackageVersion Update="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.7" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ private static IResourceBuilder<T> WithJolokiaHealthCheck<T>(
const int statusCode = 200;
const string endpointName = "web";
const string scheme = "http";
EndpointReference endpoint = builder.Resource.GetEndpoint(endpointName);

builder.ApplicationBuilder.Eventing.Subscribe<AfterEndpointsAllocatedEvent>((_, _) =>
builder.OnResourceEndpointsAllocated((resource, @event, ct) =>
{
var endpoint = resource.GetEndpoint(endpointName);
if (!endpoint.Exists)
{
throw new DistributedApplicationException($"The endpoint '{endpointName}' does not exist on the resource '{builder.Resource.Name}'.");
Expand All @@ -173,11 +173,12 @@ private static IResourceBuilder<T> WithJolokiaHealthCheck<T>(

Uri? uri = null;
string basicAuthentication = string.Empty;
builder.ApplicationBuilder.Eventing.Subscribe<BeforeResourceStartedEvent>(builder.Resource, async (_, ct) =>
builder.OnBeforeResourceStarted(async (resource, _, ct) =>
{
Uri baseUri = new Uri(endpoint.Url, UriKind.Absolute);
string userName = (await builder.Resource.UserNameReference.GetValueAsync(ct))!;
string password = (await ((IValueProvider)builder.Resource.PasswordParameter).GetValueAsync(ct))!;
var endpoint = resource.GetEndpoint(endpointName);
Uri baseUri = new (endpoint.Url, UriKind.Absolute);
string userName = (await resource.UserNameReference.GetValueAsync(ct))!;
string password = (await resource.PasswordParameter.GetValueAsync(ct))!;
basicAuthentication = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{userName}:{password}"));
uri = new UriBuilder(baseUri)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,21 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,
}
}

internal static void ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
internal static async Task ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
{
var mysqlInstances = applicationBuilder.Resources.OfType<MySqlServerResource>();

string ADMINER_SERVERS = context.EnvironmentVariables.GetValueOrDefault("ADMINER_SERVERS")?.ToString() ?? string.Empty;

var new_servers = mysqlInstances.ToDictionary(
mysqlServer => mysqlServer.Name,
mysqlServer =>
async mysqlServer =>
{
return new AdminerLoginServer
{
Server = mysqlServer.Name,
UserName = "root",
Password = mysqlServer.PasswordParameter.Value,
Password = await mysqlServer.PasswordParameter.GetValueAsync(default),
Driver = "server" // driver for MySQL is called 'server'
};
});
Expand All @@ -166,7 +166,7 @@ internal static void ConfigureAdminerContainer(EnvironmentCallbackContext contex
{
if (!servers.ContainsKey(server.Key))
{
servers!.Add(server.Key, server.Value);
servers!.Add(server.Key, await server.Value);
}
}
string servers_json = JsonSerializer.Serialize(servers);
Expand Down
27 changes: 13 additions & 14 deletions src/CommunityToolkit.Aspire.Hosting.Ngrok/NgrokExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static IResourceBuilder<NgrokResource> AddNgrok(
ArgumentNullException.ThrowIfNull(builder);
if (configurationFolder is not null)
ArgumentException.ThrowIfNullOrWhiteSpace(configurationFolder);

if (endpointPort is not null)
{
ArgumentOutOfRangeException.ThrowIfLessThan(endpointPort.Value, 1, nameof(endpointPort));
Expand All @@ -49,28 +49,27 @@ public static IResourceBuilder<NgrokResource> AddNgrok(
configurationFolder ??= Path.Combine(builder.AppHostDirectory, ".ngrok");
if (!Directory.Exists(configurationFolder))
Directory.CreateDirectory(configurationFolder);

var resource = new NgrokResource(name);
var resourceBuilder = builder.AddResource(resource)

var resourceBuilder = builder.AddResource(new NgrokResource(name))
.WithImage(NgrokContainerValues.Image, NgrokContainerValues.Tag)
.WithImageRegistry(NgrokContainerValues.Registry)
.WithBindMount(configurationFolder, "/var/tmp/ngrok")
.WithHttpEndpoint(targetPort: 4040, port: endpointPort, name: endpointName);
builder.Eventing.Subscribe<AfterEndpointsAllocatedEvent>(async (e, ct) =>
resourceBuilder.OnResourceEndpointsAllocated(async (resource, e, ct) =>
{
var endpointTuples = resource.Annotations
.OfType<NgrokEndpointAnnotation>()
.SelectMany(annotation => annotation.Endpoints.Select(ngrokEndpoint => (endpointRefernce: annotation.Resource.GetEndpoint(ngrokEndpoint.EndpointName), ngrokEndpoint)))
.ToList();
await CreateNgrokConfigurationFileAsync(configurationFolder, name, endpointTuples, configurationVersion ?? 3);

resourceBuilder.WithArgs(
"start", endpointTuples.Count > 0 ? "--all" : "--none",
"start", endpointTuples.Count > 0 ? "--all" : "--none",
"--config", $"/var/tmp/ngrok/{name}.yml");
});
return resourceBuilder;
}

/// <summary>
/// Adds a ngrok auth token to a ngrok resource.
/// </summary>
Expand All @@ -86,7 +85,7 @@ public static IResourceBuilder<NgrokResource> WithAuthToken(

return builder.WithEnvironment(NgrokContainerValues.AuthTokenEnvName, ngrokAuthToken);
}

/// <summary>
/// Adds a ngrok auth token to a ngrok resource.
/// </summary>
Expand All @@ -102,13 +101,13 @@ public static IResourceBuilder<NgrokResource> WithAuthToken(

return builder.WithEnvironment(NgrokContainerValues.AuthTokenEnvName, ngrokAuthToken);
}

/// <summary>
/// Configures a resource with endpoints as a ngrok tunnel endpoint.
/// </summary>
/// <typeparam name="TResource">The resource type.</typeparam>
public static IResourceBuilder<NgrokResource> WithTunnelEndpoint<TResource>(
this IResourceBuilder<NgrokResource> builder,
this IResourceBuilder<NgrokResource> builder,
IResourceBuilder<TResource> resource,
string endpointName,
string? ngrokUrl = null,
Expand Down Expand Up @@ -136,7 +135,7 @@ public static IResourceBuilder<NgrokResource> WithTunnelEndpoint<TResource>(

return builder;
}

private static async Task CreateNgrokConfigurationFileAsync(
string configurationFolder,
string name,
Expand Down Expand Up @@ -165,7 +164,7 @@ private static async Task CreateNgrokConfigurationFileAsync(
break;
case 3:
ngrokConfig.AppendLine("agent:");
ngrokConfig.AppendLine( " log: stdout");
ngrokConfig.AppendLine(" log: stdout");
if (endpointTuples.Count > 0)
{
ngrokConfig.AppendLine();
Expand All @@ -190,7 +189,7 @@ private static async Task CreateNgrokConfigurationFileAsync(
private static string GetUpstreamUrl(EndpointReference endpoint)
{
var isLocal = endpoint.Host.Equals("localhost", StringComparison.InvariantCultureIgnoreCase);
var host = (IsWindows || IsOsx) && isLocal? "host.docker.internal" : endpoint.Host;
var host = (IsWindows || IsOsx) && isLocal ? "host.docker.internal" : endpoint.Host;
return $"{endpoint.Scheme}://{host}:{endpoint.Port}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static IResourceBuilder<PostgresServerResource> WithDbGate(this IResource
var dbGateBuilder = DbGateBuilderExtensions.AddDbGate(builder.ApplicationBuilder, containerName);

dbGateBuilder
.WithEnvironment(context => ConfigureDbGateContainer(context, builder.ApplicationBuilder));
.WithEnvironment(context => ConfigureDbGateContainer(context, builder.ApplicationBuilder));

configureContainer?.Invoke(dbGateBuilder);

Expand Down Expand Up @@ -105,9 +105,9 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,

foreach (var postgresServer in postgresInstances)
{
var userParameter = postgresServer.UserNameParameter is null
? ReferenceExpression.Create($"postgres")
: ReferenceExpression.Create($"{postgresServer.UserNameParameter}");
var userParameter = postgresServer.UserNameParameter is null
? ReferenceExpression.Create($"postgres")
: ReferenceExpression.Create($"{postgresServer.UserNameParameter}");

// DbGate assumes Postgres is being accessed over a default Aspire container network and hardcodes the resource address
// This will need to be refactored once updated service discovery APIs are available
Expand Down Expand Up @@ -141,22 +141,30 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,
}


internal static void ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
internal static async Task ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
{
var postgresInstances = applicationBuilder.Resources.OfType<PostgresServerResource>();

string ADMINER_SERVERS = context.EnvironmentVariables.GetValueOrDefault("ADMINER_SERVERS")?.ToString() ?? string.Empty;

var new_servers = postgresInstances.ToDictionary(
postgresServer => postgresServer.Name,
postgresServer =>
async postgresServer =>
{
var user = postgresServer.UserNameParameter?.Value ?? "postgres";
var user = postgresServer.UserNameParameter switch
{
null => "postgres",
_ => await postgresServer.UserNameParameter.GetValueAsync(default)
};
return new AdminerLoginServer
{
Server = postgresServer.Name,
UserName = user,
Password = postgresServer.PasswordParameter.Value,
Password = postgresServer.PasswordParameter switch
{
null => string.Empty,
_ => await postgresServer.PasswordParameter.GetValueAsync(default)
},
Driver = "pgsql"
};
});
Expand All @@ -173,7 +181,7 @@ internal static void ConfigureAdminerContainer(EnvironmentCallbackContext contex
{
if (!servers.ContainsKey(server.Key))
{
servers!.Add(server.Key, server.Value);
servers!.Add(server.Key, await server.Value);
}
}
string servers_json = JsonSerializer.Serialize(servers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,21 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,
}
}

private static void ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
private static async Task ConfigureAdminerContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
{
var sqlServerInstances = applicationBuilder.Resources.OfType<SqlServerServerResource>();

string ADMINER_SERVERS = context.EnvironmentVariables.GetValueOrDefault("ADMINER_SERVERS")?.ToString() ?? string.Empty;

var new_servers = sqlServerInstances.ToDictionary(
sqlServerServerResource => sqlServerServerResource.Name,
sqlServerServerResource =>
async sqlServerServerResource =>
{
return new AdminerLoginServer
{
Server = sqlServerServerResource.Name,
UserName = "sa",
Password = sqlServerServerResource.PasswordParameter.Value,
Password = await sqlServerServerResource.PasswordParameter.GetValueAsync(default),
Driver = "mssql"
};
});
Expand All @@ -166,7 +166,7 @@ private static void ConfigureAdminerContainer(EnvironmentCallbackContext context
{
if (!servers.ContainsKey(server.Key))
{
servers!.Add(server.Key, server.Value);
servers!.Add(server.Key, await server.Value);
}
}
string servers_json = JsonSerializer.Serialize(servers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
{
foreach (var secretAnnotation in secretAnnotations)
{
secrets[secretAnnotation.Key] = (await ((IValueProvider)secretAnnotation).GetValueAsync(cancellationToken))!;
secrets[secretAnnotation.Key] = (await secretAnnotation.Value.GetValueAsync(cancellationToken))!;
}
// We need to append the secret store path to the resources path
onDemandResourcesPaths.TryGetValue("secretstore", out var secretStorePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static IResourceBuilder<IDaprComponentResource> WithMetadata(this IResour
schema.Spec.Metadata.Add(new DaprComponentSpecMetadataValue
{
Name = name,
Value = (await ((IValueProvider)parameterResource).GetValueAsync(default))!
Value = (await parameterResource.GetValueAsync(default))!
});
}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void AddActiveMqApiBuilderSchemeShouldNotBeNullOrWhiteSpace()
}

[Fact]
public void AddActiveMqApiBuilderContainerDetailsSetOnResource()
public async Task AddActiveMqApiBuilderContainerDetailsSetOnResource()
{
IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder();

Expand All @@ -44,8 +44,8 @@ public void AddActiveMqApiBuilderContainerDetailsSetOnResource()

Assert.NotNull(resource);
Assert.Equal("amq", resource.Name);
Assert.Equal("admin", resource.UserNameParameter!.Value);
Assert.Equal("admin", resource.PasswordParameter.Value);
Assert.Equal("admin", await resource.UserNameParameter!.GetValueAsync(default));
Assert.Equal("admin", await resource.PasswordParameter.GetValueAsync(default));
Assert.Equal("ACTIVEMQ_CONNECTION_PASSWORD", resource.ActiveMqSettings.EnvironmentVariablePassword);
Assert.Equal("ACTIVEMQ_CONNECTION_USER", resource.ActiveMqSettings.EnvironmentVariableUsername);

Expand All @@ -59,7 +59,7 @@ public void AddActiveMqApiBuilderContainerDetailsSetOnResource()
}

[Fact]
public void AddActiveMqArtemisApiBuilderContainerDetailsSetOnResource()
public async Task AddActiveMqArtemisApiBuilderContainerDetailsSetOnResource()
{
IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder();

Expand All @@ -74,8 +74,8 @@ public void AddActiveMqArtemisApiBuilderContainerDetailsSetOnResource()

Assert.NotNull(resource);
Assert.Equal("amq", resource.Name);
Assert.Equal("admin", resource.UserNameParameter!.Value);
Assert.Equal("admin", resource.PasswordParameter.Value);
Assert.Equal("admin", await resource.UserNameParameter!.GetValueAsync(default));
Assert.Equal("admin", await resource.PasswordParameter.GetValueAsync(default));
Assert.Equal("ARTEMIS_PASSWORD", resource.ActiveMqSettings.EnvironmentVariablePassword);
Assert.Equal("ARTEMIS_USER", resource.ActiveMqSettings.EnvironmentVariableUsername);

Expand Down
Loading
Loading