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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"commandName": "Project",
"launchBrowser": true,
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:15888",
"applicationUrl": "https://localhost:15887;http://localhost:15888",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
Expand Down
40 changes: 34 additions & 6 deletions src/Aspire.Hosting/Dcp/ApplicationExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Net.Sockets;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Dashboard;
Expand Down Expand Up @@ -198,7 +199,7 @@ private async Task StartDashboardAsDcpExecutableAsync(CancellationToken cancella
}

var otlpEndpointUrl = environmentVariables.GetString("DOTNET_DASHBOARD_OTLP_ENDPOINT_URL");
var dashboardUrl = environmentVariables.GetString("ASPNETCORE_URLS") ?? throw new DistributedApplicationException("ASPNETCORE_URLS environment variable not set.");
var dashboardUrls = environmentVariables.GetString("ASPNETCORE_URLS") ?? throw new DistributedApplicationException("ASPNETCORE_URLS environment variable not set.");
var aspnetcoreEnvironment = environmentVariables.GetString("ASPNETCORE_ENVIRONMENT");

dashboardExecutableSpec.Env =
Expand All @@ -211,7 +212,7 @@ private async Task StartDashboardAsDcpExecutableAsync(CancellationToken cancella
new()
{
Name = "ASPNETCORE_URLS",
Value = dashboardUrl
Value = dashboardUrls
},
new()
{
Expand All @@ -231,7 +232,7 @@ private async Task StartDashboardAsDcpExecutableAsync(CancellationToken cancella
};

await kubernetesService.CreateAsync(dashboardExecutable, cancellationToken).ConfigureAwait(false);
await WaitForHttpSuccessOrThrow(dashboardUrl, DashboardAvailabilityTimeoutDuration, cancellationToken).ConfigureAwait(false);
await CheckDashboardAvailabilityAsync(dashboardUrls, cancellationToken).ConfigureAwait(false);
}

private static TimeSpan DashboardAvailabilityTimeoutDuration
Expand All @@ -251,7 +252,19 @@ private static TimeSpan DashboardAvailabilityTimeoutDuration

private const int DefaultDashboardAvailabilityTimeoutDurationInSeconds = 60;

private async Task WaitForHttpSuccessOrThrow(string url, TimeSpan timeout, CancellationToken cancellationToken = default)
private async Task CheckDashboardAvailabilityAsync(string delimitedUrlList, CancellationToken cancellationToken)
{
if (TryGetUriFromDelimitedString(delimitedUrlList, ";", out var firstDashboardUrl))
{
await WaitForHttpSuccessOrThrow(firstDashboardUrl, DashboardAvailabilityTimeoutDuration, cancellationToken).ConfigureAwait(false);
}
else
{
_logger.LogWarning("Skipping dashboard availability check because ASPNETCORE_URLS environment variable could not be parsed.");
}
}

private async Task WaitForHttpSuccessOrThrow(Uri url, TimeSpan timeout, CancellationToken cancellationToken = default)
{
using var timeoutCts = new CancellationTokenSource(timeout);
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
Expand Down Expand Up @@ -639,12 +652,12 @@ private async Task CreateExecutablesAsync(IEnumerable<AppResource> executableRes
{
// We just check the HTTP endpoint because this will prove that the
// dashboard is listening and is ready to process requests.
if (Environment.GetEnvironmentVariable("ASPNETCORE_URLS") is not { } dashboardUrl)
if (Environment.GetEnvironmentVariable("ASPNETCORE_URLS") is not { } dashboardUrls)
{
throw new DistributedApplicationException("Cannot check dashboard availability since ASPNETCORE_URLS environment variable not set.");
}

await WaitForHttpSuccessOrThrow(dashboardUrl, DashboardAvailabilityTimeoutDuration, cancellationToken).ConfigureAwait(false);
await CheckDashboardAvailabilityAsync(dashboardUrls, cancellationToken).ConfigureAwait(false);
}

}
Expand All @@ -656,6 +669,21 @@ private async Task CreateExecutablesAsync(IEnumerable<AppResource> executableRes
}
}

private static bool TryGetUriFromDelimitedString(string input, string delimiter, [NotNullWhen(true)]out Uri? uri)
{
if (!string.IsNullOrEmpty(input)
&& input.Split(delimiter) is { Length: > 0} splitInput
&& Uri.TryCreate(splitInput[0], UriKind.Absolute, out uri))
{
return true;
}
else
{
uri = null;
return false;
}
}

private static void ApplyLaunchProfile(AppResource executableResource, Dictionary<string, string> config, string launchProfileName, LaunchSettings launchSettings)
{
// Populate DOTNET_LAUNCH_PROFILE environment variable for consistency with "dotnet run" and "dotnet watch".
Expand Down