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 @@ -10,19 +10,19 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
}
},
"generate-manifest": {
"commandName": "Project",
"launchBrowser": true,
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
"applicationUrl": "http://localhost:15888",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175"
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
},
"generate-manifest": {
"commandName": "Project",
"launchBrowser": true,
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
"applicationUrl": "http://localhost:15888",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175"
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
// to test end developer dashboard launch experience. Refer to Directory.Build.props
// for the path to the dashboard binary (defaults to the Aspire.Dashboard bin output
// in the artifacts dir).
//builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard);
builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard);

builder.Build().Run();
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"generate-manifest": {
Expand Down
2 changes: 1 addition & 1 deletion playground/dapr/AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16031",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"generate-manifest": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16031",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"generate-manifest": {
Expand Down
3 changes: 2 additions & 1 deletion playground/eShopLite/AppHost/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"generate-manifest": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16031",
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" // Display dashboard resource in console for local development
"DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"generate-manifest": {
Expand Down
19 changes: 19 additions & 0 deletions src/Aspire.Hosting/Dashboard/DashboardManifestExclusionHook.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.Lifecycle;

namespace Aspire.Hosting.Dashboard;
internal sealed class DashboardManifestExclusionHook : IDistributedApplicationLifecycleHook
{
public Task BeforeStartAsync(DistributedApplicationModel model, CancellationToken cancellationToken)
{
if (model.Resources.SingleOrDefault(r => StringComparers.ResourceName.Equals(r.Name, KnownResourceNames.AspireDashboard)) is { } dashboardResource)
{
dashboardResource.Annotations.Add(ManifestPublishingCallbackAnnotation.Ignore);
}

return Task.CompletedTask;
}
}
27 changes: 8 additions & 19 deletions src/Aspire.Hosting/Dcp/ApplicationExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// 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;
using Aspire.Hosting.Dcp.Model;
using Aspire.Hosting.Lifecycle;
using Aspire.Hosting.Utils;
using k8s;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand Down Expand Up @@ -50,6 +50,7 @@ public ServiceAppResource(IResource modelResource, Service service, EndpointAnno
}

internal sealed class ApplicationExecutor(ILogger<ApplicationExecutor> logger,
ILoggerFactory loggerFactory,
DistributedApplicationModel model,
DistributedApplicationOptions distributedApplicationOptions,
KubernetesService kubernetesService,
Expand Down Expand Up @@ -138,12 +139,12 @@ private async Task ConfigureAspireDashboardResource(IResource dashboardResource,
{
if (Environment.GetEnvironmentVariable("ASPNETCORE_URLS") is not { } appHostApplicationUrl)
{
throw new DistributedApplicationException("Dashboard inner loop hook failed to configure resource because ASPNETCORE_URLS environment variable was not set.");
throw new DistributedApplicationException("Failed to configure dashboard resource because ASPNETCORE_URLS environment variable was not set.");
}

if (Environment.GetEnvironmentVariable("DOTNET_DASHBOARD_OTLP_ENDPOINT_URL") is not { } otlpEndpointUrl)
{
throw new DistributedApplicationException("Dashboard inner loop hook failed to configure resource because DOTNET_DASHBOARD_OTLP_ENDPOINT_URL environment variable was not set.");
throw new DistributedApplicationException("Failed to configure dashboard resource because DOTNET_DASHBOARD_OTLP_ENDPOINT_URL environment variable was not set.");
}

// Grab the resource service URL. We need to inject this into the resource.
Expand Down Expand Up @@ -254,9 +255,12 @@ private static TimeSpan DashboardAvailabilityTimeoutDuration

private async Task CheckDashboardAvailabilityAsync(string delimitedUrlList, CancellationToken cancellationToken)
{
if (TryGetUriFromDelimitedString(delimitedUrlList, ";", out var firstDashboardUrl))
if (StringUtils.TryGetUriFromDelimitedString(delimitedUrlList, ";", out var firstDashboardUrl))
{
await WaitForHttpSuccessOrThrow(firstDashboardUrl, DashboardAvailabilityTimeoutDuration, cancellationToken).ConfigureAwait(false);

var distributedApplicationLogger = loggerFactory.CreateLogger<DistributedApplication>();
distributedApplicationLogger.LogInformation("Now listening on: {DashboardUrl}", firstDashboardUrl.ToString().TrimEnd('/'));
}
else
{
Expand Down Expand Up @@ -669,21 +673,6 @@ 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
36 changes: 17 additions & 19 deletions src/Aspire.Hosting/DistributedApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Aspire.Hosting.Publishing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Aspire.Hosting;
Expand Down Expand Up @@ -46,6 +46,7 @@ public class DistributedApplication : IHost, IAsyncDisposable
{
private readonly IHost _host;
private readonly string[] _args;
private readonly ILogger<DistributedApplication> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="DistributedApplication"/> class.
Expand All @@ -55,6 +56,7 @@ public class DistributedApplication : IHost, IAsyncDisposable
public DistributedApplication(IHost host, string[] args)
{
_host = host;
_logger = host.Services.GetRequiredService<ILogger<DistributedApplication>>();
_args = args;
}

Expand Down Expand Up @@ -111,8 +113,9 @@ public ValueTask DisposeAsync()
/// <inheritdoc cref="IHost.StartAsync" />
public async Task StartAsync(CancellationToken cancellationToken = default)
{
await ExecuteBeforeStartHooksAsync(cancellationToken).ConfigureAwait(false);
WriteStartingLog();
await _host.StartAsync(cancellationToken).ConfigureAwait(false);
await ExecuteBeforeStartHooksAsync(cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc cref="IHost.StopAsync" />
Expand All @@ -121,30 +124,25 @@ public async Task StopAsync(CancellationToken cancellationToken = default)
await _host.StopAsync(cancellationToken).ConfigureAwait(false);
}

private void SuppressLifetimeLogsDuringManifestPublishing()
/// <inheritdoc cref="HostingAbstractionsHostExtensions.RunAsync" />
public async Task RunAsync(CancellationToken cancellationToken = default)
{
WriteStartingLog();
await ExecuteBeforeStartHooksAsync(cancellationToken).ConfigureAwait(false);
await _host.RunAsync(cancellationToken).ConfigureAwait(false);
}

private void WriteStartingLog()
{
var config = (IConfigurationRoot)_host.Services.GetRequiredService<IConfiguration>();
var options = _host.Services.GetRequiredService<IOptions<PublishingOptions>>();

if (options.Value?.Publisher != "manifest")
if (options.Value?.Publisher == "manifest")
{
// If we aren't doing manifest publishing we want the logs
// to be produced as normal.
// If we are producing the manifest, don't write startup messages.
return;
}

var hostingLifetimeLoggingLevelSection = config.GetSection("Logging:LogLevel:Microsoft.Hosting.Lifetime");
hostingLifetimeLoggingLevelSection.Value = "Warning";

config.Reload();
}

/// <inheritdoc cref="HostingAbstractionsHostExtensions.RunAsync" />
public async Task RunAsync(CancellationToken cancellationToken = default)
{
SuppressLifetimeLogsDuringManifestPublishing();
await ExecuteBeforeStartHooksAsync(cancellationToken).ConfigureAwait(false);
await _host.RunAsync(cancellationToken).ConfigureAwait(false);
_logger.LogInformation("Distributed application starting.");
}

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Hosting/DistributedApplicationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Aspire.Hosting;

Expand Down Expand Up @@ -44,6 +45,9 @@ public DistributedApplicationBuilder(DistributedApplicationOptions options)
_args = options.Args ?? [];
_innerBuilder = new HostApplicationBuilder();

_innerBuilder.Logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning);
_innerBuilder.Logging.AddFilter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.None);

AppHostDirectory = options.ProjectDirectory ?? _innerBuilder.Environment.ContentRootPath;

// Make the app host directory available to the application via configuration
Expand All @@ -61,6 +65,7 @@ public DistributedApplicationBuilder(DistributedApplicationOptions options)
// Dashboard
_innerBuilder.Services.AddSingleton<DashboardServiceHost>();
_innerBuilder.Services.AddHostedService<DashboardServiceHost>(sp => sp.GetRequiredService<DashboardServiceHost>());
_innerBuilder.Services.AddLifecycleHook<DashboardManifestExclusionHook>();

// DCP stuff
_innerBuilder.Services.AddLifecycleHook<DcpDistributedApplicationLifecycleHook>();
Expand Down
25 changes: 25 additions & 0 deletions src/Aspire.Hosting/Utils/StringUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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;

namespace Aspire.Hosting.Utils;

internal static class StringUtils
{
public 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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void BuilderAddsDefaultServices()

var lifecycles = app.Services.GetServices<IDistributedApplicationLifecycleHook>();
Assert.Single(lifecycles.Where(h => h.GetType().Name == "DcpDistributedApplicationLifecycleHook"));
Assert.Equal(3, lifecycles.Count());
Assert.Equal(4, lifecycles.Count());

var options = app.Services.GetRequiredService<IOptions<PublishingOptions>>();
Assert.Null(options.Value.Publisher);
Expand Down