diff --git a/playground/eShopLite/AppHost/Properties/launchSettings.json b/playground/eShopLite/AppHost/Properties/launchSettings.json index f752c9e26b6..10744f258fa 100644 --- a/playground/eShopLite/AppHost/Properties/launchSettings.json +++ b/playground/eShopLite/AppHost/Properties/launchSettings.json @@ -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", diff --git a/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs b/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs index dfed6188a9e..c55a261698b 100644 --- a/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs +++ b/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs @@ -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; @@ -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 = @@ -211,7 +212,7 @@ private async Task StartDashboardAsDcpExecutableAsync(CancellationToken cancella new() { Name = "ASPNETCORE_URLS", - Value = dashboardUrl + Value = dashboardUrls }, new() { @@ -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 @@ -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); @@ -639,12 +652,12 @@ private async Task CreateExecutablesAsync(IEnumerable 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); } } @@ -656,6 +669,21 @@ private async Task CreateExecutablesAsync(IEnumerable 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 config, string launchProfileName, LaunchSettings launchSettings) { // Populate DOTNET_LAUNCH_PROFILE environment variable for consistency with "dotnet run" and "dotnet watch".