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
18 changes: 17 additions & 1 deletion src/Aspire.Hosting/ProjectResourceBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,27 @@ private static IResourceBuilder<ProjectResource> WithProjectDefaults(this IResou
if (!kestrelEndpointsByScheme.Any())
{
var urlsFromApplicationUrl = launchProfile.ApplicationUrl?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? [];
Dictionary<string, int> endpointCountByScheme = [];
foreach (var url in urlsFromApplicationUrl)
{
var uri = new Uri(url);

builder.WithEndpoint(uri.Scheme, e =>
// Keep track of how many endpoints we have for each scheme
endpointCountByScheme.TryGetValue(uri.Scheme, out var count);
endpointCountByScheme[uri.Scheme] = count + 1;

// If we have multiple for the same scheme, we differentiate them by appending a number.
// We only do this starting with the second endpoint, so that the first stays just http/https.
// This allows us to keep the same behavior as "dotnet run".
// Also, note that we only do this in Run mode, as in Publish mode those extra endpoints
// with generic names would not be easily usable.
var endpointName = uri.Scheme;
if (endpointCountByScheme[uri.Scheme] > 1)
{
endpointName += endpointCountByScheme[uri.Scheme];
}

builder.WithEndpoint(endpointName, e =>
{
e.Port = uri.Port;
e.UriScheme = uri.Scheme;
Expand Down
50 changes: 50 additions & 0 deletions tests/Aspire.Hosting.Tests/ProjectResourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,35 @@ public async Task ProjectWithLaunchProfileAddsHttpOrHttpsEndpointAddsToEnv()
Assert.False(config.ContainsKey("ASPNETCORE_HTTPS_PORT"));
}

[Fact]
public async Task ProjectWithMultipleLaunchProfileAppUrlsGetsAllUrls()
{
var appBuilder = CreateBuilder(operation: DistributedApplicationOperation.Run);

var builder = appBuilder.AddProject<TestProjectWithManyAppUrlsInLaunchSettings>("projectName");

// Need to allocated all the endpoints we get from the launch profile applicationUrl
var index = 0;
foreach (var q in new[] { "http", "http2", "https", "https2", "https3" })
{
builder.WithEndpoint(q, e =>
{
e.AllocatedEndpoint = new(e, "localhost", e.Port!.Value, targetPortExpression: $"p{index++}");
});
}

using var app = appBuilder.Build();
var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
var projectResources = appModel.GetProjectResources();
var resource = Assert.Single(projectResources);
var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance);

Assert.Equal("https://localhost:p2;http://localhost:p0;http://localhost:p1;https://localhost:p3;https://localhost:p4", config["ASPNETCORE_URLS"]);

// The first https port is the one that should be used for ASPNETCORE_HTTPS_PORT
Assert.Equal("7144", config["ASPNETCORE_HTTPS_PORT"]);
}

[Fact]
public void DisabledForwardedHeadersAddsAnnotationToProject()
{
Expand Down Expand Up @@ -618,4 +647,25 @@ public TestProjectWithLaunchSettings()
};
}
}

private sealed class TestProjectWithManyAppUrlsInLaunchSettings : BaseProjectWithProfileAndConfig
{
public TestProjectWithManyAppUrlsInLaunchSettings()
{
Profiles = new()
{
["https"] = new()
{
CommandName = "Project",
CommandLineArgs = "arg1 arg2",
LaunchBrowser = true,
ApplicationUrl = "https://localhost:7144;http://localhost:5193;http://localhost:5194;https://localhost:7145;https://localhost:7146",
EnvironmentVariables = new()
{
["ASPNETCORE_ENVIRONMENT"] = "Development"
}
}
};
}
}
}