From 90a9fc6cf0209c825116bd624a7c391074421038 Mon Sep 17 00:00:00 2001 From: afscrome Date: Sun, 1 Feb 2026 23:10:23 +0000 Subject: [PATCH 1/7] Refactor endpoint resolution logic so that `EndpointReferenceExpression.GetValueAsync()` can be context aware. To make this work, DCP now always allocates a `DefaultAspireContainerNetwork` endpoint when a container is created alongside the existing `LocalhostNetwork` endpoint. --- .../ApplicationModel/ExpressionResolver.cs | 29 ----- src/Aspire.Hosting/Dcp/DcpExecutor.cs | 23 ++++ .../Dcp/DcpExecutorTests.cs | 102 +++++++++++++++++- .../EndpointReferenceTests.cs | 84 +++++++++++++++ .../ExpressionResolverTests.cs | 42 +++++--- 5 files changed, 235 insertions(+), 45 deletions(-) diff --git a/src/Aspire.Hosting/ApplicationModel/ExpressionResolver.cs b/src/Aspire.Hosting/ApplicationModel/ExpressionResolver.cs index b430a9c7b47..c483a8a2360 100644 --- a/src/Aspire.Hosting/ApplicationModel/ExpressionResolver.cs +++ b/src/Aspire.Hosting/ApplicationModel/ExpressionResolver.cs @@ -8,32 +8,6 @@ namespace Aspire.Hosting.ApplicationModel; internal class ExpressionResolver(CancellationToken cancellationToken) { - - async Task ResolveInContainerContextAsync(EndpointReference endpointReference, EndpointProperty property, ValueProviderContext context) - { - // We need to use the root resource, e.g. AzureStorageResource instead of AzureBlobResource - // Otherwise, we get the wrong values for IsContainer and Name - var target = endpointReference.Resource.GetRootResource(); - - return (property, target.IsContainer()) switch - { - // If Container -> Container, we use .dev.internal as host, and target port as port - // This assumes both containers are on the same container network. - // Different networks will require addtional routing/tunneling that we do not support today. - (EndpointProperty.Host or EndpointProperty.IPV4Host, true) => $"{target.Name}.dev.internal", - (EndpointProperty.Port, true) => await endpointReference.Property(EndpointProperty.TargetPort).GetValueAsync(context, cancellationToken).ConfigureAwait(false), - - (EndpointProperty.Url, _) => string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}", - endpointReference.Scheme, - await ResolveInContainerContextAsync(endpointReference, EndpointProperty.Host, context).ConfigureAwait(false), - await ResolveInContainerContextAsync(endpointReference, EndpointProperty.Port, context).ConfigureAwait(false)), - (EndpointProperty.HostAndPort, _) => string.Format(CultureInfo.InvariantCulture, "{0}:{1}", - await ResolveInContainerContextAsync(endpointReference, EndpointProperty.Host, context).ConfigureAwait(false), - await ResolveInContainerContextAsync(endpointReference, EndpointProperty.Port, context).ConfigureAwait(false)), - _ => await endpointReference.Property(property).GetValueAsync(context, cancellationToken).ConfigureAwait(false) - }; - } - async Task EvalExpressionAsync(ReferenceExpression expr, ValueProviderContext context) { // This logic is similar to ReferenceExpression.GetValueAsync, except that we recurse on @@ -95,14 +69,11 @@ async Task ResolveConnectionStringReferenceAsync(ConnectionString /// async ValueTask ResolveInternalAsync(object? value, ValueProviderContext context) { - var networkContext = context.GetNetworkIdentifier(); return value switch { ConnectionStringReference cs => await ResolveConnectionStringReferenceAsync(cs, context).ConfigureAwait(false), IResourceWithConnectionString cs and not ConnectionStringParameterResource => await ResolveInternalAsync(cs.ConnectionStringExpression, context).ConfigureAwait(false), ReferenceExpression ex => await EvalExpressionAsync(ex, context).ConfigureAwait(false), - EndpointReference er when er.ContextNetworkID == KnownNetworkIdentifiers.DefaultAspireContainerNetwork || (er.ContextNetworkID == null && networkContext == KnownNetworkIdentifiers.DefaultAspireContainerNetwork) => new ResolvedValue(await ResolveInContainerContextAsync(er, EndpointProperty.Url, context).ConfigureAwait(false), false), - EndpointReferenceExpression ep when ep.Endpoint.ContextNetworkID == KnownNetworkIdentifiers.DefaultAspireContainerNetwork || (ep.Endpoint.ContextNetworkID == null && networkContext == KnownNetworkIdentifiers.DefaultAspireContainerNetwork) => new ResolvedValue(await ResolveInContainerContextAsync(ep.Endpoint, ep.Property, context).ConfigureAwait(false), false), IValueProvider vp => await EvalValueProvider(vp, context).ConfigureAwait(false), _ => throw new NotImplementedException() }; diff --git a/src/Aspire.Hosting/Dcp/DcpExecutor.cs b/src/Aspire.Hosting/Dcp/DcpExecutor.cs index 27c57963bd2..2434f1ee78f 100644 --- a/src/Aspire.Hosting/Dcp/DcpExecutor.cs +++ b/src/Aspire.Hosting/Dcp/DcpExecutor.cs @@ -977,6 +977,28 @@ private void AddAllocatedEndpointInfo(IEnumerable resourc bindingMode, targetPortExpression: $$$"""{{- portForServing "{{{svc.Metadata.Name}}}" -}}""", KnownNetworkIdentifiers.LocalhostNetwork); + + if (appResource.DcpResource is Container ctr && ctr.Spec.Networks is not null) + { + foreach (var network in ctr.Spec.Networks) + { + var networkID = new NetworkIdentifier(network.Name!); + var address = network.Aliases!.Last(); // relying on an implementation detail here to ensure we get the `*.dev.internal` alias + var port = sp.EndpointAnnotation.TargetPort!; + + var tunnelAllocatedEndpoint = new AllocatedEndpoint( + sp.EndpointAnnotation, + address, + (int)port, + EndpointBindingMode.SingleAddress, + targetPortExpression: $$$"""{{- portForServing "{{{svc.Metadata.Name}}}" -}}""", + networkID + ); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(tunnelAllocatedEndpoint); + sp.EndpointAnnotation.AllAllocatedEndpoints.TryAdd(networkID, snapshot); + } + } } } @@ -1040,6 +1062,7 @@ ts.Service is not null && } } } + } private void PrepareContainerNetworks() diff --git a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs index 8840c964dd1..e1527505eb4 100644 --- a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs +++ b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs @@ -1000,7 +1000,7 @@ public async Task EndpointPortsConainerProxiedNoPortTargetPortSet() } [Fact] - public async Task EndpointPortsConainerProxiedPortAndTargetPortSet() + public async Task EndpointPortsContainerProxiedPortAndTargetPortSet() { var builder = DistributedApplication.CreateBuilder(); @@ -2175,6 +2175,106 @@ public async Task ProjectExecutable_NoSupportsDebuggingAnnotation_RunsInProcessM Assert.Equal(ExecutionType.Process, exe.Spec.ExecutionType); } + [Theory] + [InlineData(true, null, "aspire.dev.internal")] + [InlineData(false, null, "host.docker.internal")] + [InlineData(true, "super.star", "aspire.dev.internal")] + [InlineData(false, "mega.mushroom", "mega.mushroom")] + public async Task EndpointsAllocatedCorrectly2(bool useTunnel, string? containerHostName, string expectedContainerHost) + { + var builder = DistributedApplication.CreateBuilder(); + var executable = builder.AddExecutable("anExecutable", "command", "") + .WithEndpoint(name: "proxied", targetPort: 1234, port: 5678, isProxied: true) + .WithEndpoint(name: "notProxied", port: 8765, isProxied: false); + + var container = builder.AddContainer("aContainer", "image") + .WithEndpoint(name: "proxied", port: 15678, targetPort: 11234, isProxied: true) + .WithEndpoint(name: "notProxied", port: 18765, isProxied: false); + + var containerWithAlias = builder.AddContainer("containerWithAlias", "image") + .WithEndpoint(name: "proxied", port: 25678, targetPort: 21234, isProxied: true) + .WithEndpoint(name: "notProxied", port: 28765, isProxied: false) + .WithContainerNetworkAlias("custom.alias"); + + var kubernetesService = new TestKubernetesService(); + using var app = builder.Build(); + var distributedAppModel = app.Services.GetRequiredService(); + + var configDict = new Dictionary + { + ["AppHost:ContainerHostname"] = containerHostName + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configDict).Build(); + + var dcpOptions = new DcpOptions + { + EnableAspireContainerTunnel = useTunnel, + }; + + var appExecutor = CreateAppExecutor(distributedAppModel, kubernetesService: kubernetesService, configuration: configuration, dcpOptions: dcpOptions); + + await appExecutor.RunApplicationAsync(); + + await AssertEndpoint(executable.Resource, "proxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 5678); + await AssertEndpoint(executable.Resource, "notProxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 8765); + + if (useTunnel) + { + await AssertTunneledPort(executable.Resource, "proxied"); + await AssertTunneledPort(executable.Resource, "notProxied"); + + async ValueTask AssertTunneledPort(IResourceWithEndpoints resource, string endpointName) + { + var svcs = kubernetesService.CreatedResources + .OfType() + .Where(x => x.AppModelResourceName == resource.Name + && x.EndpointName == endpointName + && x.Metadata.Annotations.ContainsKey(CustomResource.ContainerTunnelInstanceName)) + .ToList(); + + var svc = svcs.Single(); + + int port = svc.AllocatedPort!.Value; + await AssertEndpoint(executable.Resource, endpointName, KnownNetworkIdentifiers.DefaultAspireContainerNetwork, expectedContainerHost, port); + } + } + else + { + await AssertEndpoint(executable.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, expectedContainerHost, 5678); + await AssertEndpoint(executable.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, expectedContainerHost, 8765); + } + + await AssertEndpoint(container.Resource, "proxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 15678); + await AssertEndpoint(container.Resource, "notProxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 18765); + + await AssertEndpoint(container.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{container.Resource.Name}.dev.internal", 11234); + await AssertEndpoint(container.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{container.Resource.Name}.dev.internal", 18765); + + await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 25678); + await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 28765); + + //TODO: Not sure if this is the desired behaviour + await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, "custom.alias", 21234); + await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, "custom.alias", 28765); + + async ValueTask AssertEndpoint(IResourceWithEndpoints resource, string name, NetworkIdentifier network, string address, int port) + { + var endpoint = resource.GetEndpoint(name).EndpointAnnotation; + var allocatedEndpoints = endpoint.AllAllocatedEndpoints; + + Assert.Contains(allocatedEndpoints, a => a.NetworkID == network); + + var allocatedEndpoint = await endpoint.AllAllocatedEndpoints.Single(x => x.NetworkID == network).Snapshot.GetValueAsync().DefaultTimeout(); + + Assert.Equal(endpoint, allocatedEndpoint.Endpoint); + Assert.Equal(address, allocatedEndpoint.Address); + Assert.Equal(EndpointBindingMode.SingleAddress, allocatedEndpoint.BindingMode); + Assert.Equal(port, allocatedEndpoint.Port); + Assert.Equal(endpoint.UriScheme, allocatedEndpoint.UriScheme); + Assert.Equal($"{address}:{port}", allocatedEndpoint.EndPointString); + } + } + private static void HasKnownCommandAnnotations(IResource resource) { var commandAnnotations = resource.Annotations.OfType().ToList(); diff --git a/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs b/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs index f7fd6771288..31eae6e0cf1 100644 --- a/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs +++ b/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs @@ -285,6 +285,90 @@ public void TargetPort_ReturnsNullWhenNotDefined() Assert.Null(targetPort); } + [Theory] + [InlineData(EndpointProperty.Url, ResourceKind.Host, ResourceKind.Host, "blah://localhost:1234")] + [InlineData(EndpointProperty.Url, ResourceKind.Host, ResourceKind.Container, "blah://localhost:1234")] + [InlineData(EndpointProperty.Url, ResourceKind.Container, ResourceKind.Host, "blah://host.docker.internal:1234")] + [InlineData(EndpointProperty.Url, ResourceKind.Container, ResourceKind.Container, "blah://destination.dev.internal:4567")] + [InlineData(EndpointProperty.Host, ResourceKind.Host, ResourceKind.Host, "localhost")] + [InlineData(EndpointProperty.Host, ResourceKind.Host, ResourceKind.Container, "localhost")] + [InlineData(EndpointProperty.Host, ResourceKind.Container, ResourceKind.Host, "host.docker.internal")] + [InlineData(EndpointProperty.Host, ResourceKind.Container, ResourceKind.Container, "destination.dev.internal")] + [InlineData(EndpointProperty.IPV4Host, ResourceKind.Host, ResourceKind.Host, "127.0.0.1")] + [InlineData(EndpointProperty.IPV4Host, ResourceKind.Host, ResourceKind.Container, "127.0.0.1")] + [InlineData(EndpointProperty.IPV4Host, ResourceKind.Container, ResourceKind.Host, "host.docker.internal")] + [InlineData(EndpointProperty.IPV4Host, ResourceKind.Container, ResourceKind.Container, "destination.dev.internal")] + [InlineData(EndpointProperty.Port, ResourceKind.Host, ResourceKind.Host, "1234")] + [InlineData(EndpointProperty.Port, ResourceKind.Host, ResourceKind.Container, "1234")] + [InlineData(EndpointProperty.Port, ResourceKind.Container, ResourceKind.Host, "1234")] + [InlineData(EndpointProperty.Port, ResourceKind.Container, ResourceKind.Container, "4567")] + [InlineData(EndpointProperty.Scheme, ResourceKind.Host, ResourceKind.Host, "blah")] + [InlineData(EndpointProperty.Scheme, ResourceKind.Host, ResourceKind.Container, "blah")] + [InlineData(EndpointProperty.Scheme, ResourceKind.Container, ResourceKind.Host, "blah")] + [InlineData(EndpointProperty.Scheme, ResourceKind.Container, ResourceKind.Container, "blah")] + [InlineData(EndpointProperty.HostAndPort, ResourceKind.Host, ResourceKind.Host, "localhost:1234")] + [InlineData(EndpointProperty.HostAndPort, ResourceKind.Host, ResourceKind.Container, "localhost:1234")] + [InlineData(EndpointProperty.HostAndPort, ResourceKind.Container, ResourceKind.Host, "host.docker.internal:1234")] + [InlineData(EndpointProperty.HostAndPort, ResourceKind.Container, ResourceKind.Container, "destination.dev.internal:4567")] + public async Task PropertyResolutionTest(EndpointProperty property, ResourceKind sourceKind, ResourceKind destinationKind, object expectedResult) + { + int port = 1234; + int targetPort = 4567; + + var source = CreateResource("caller", sourceKind); + var destination = CreateResource("destination", destinationKind); + + var network = source.GetDefaultResourceNetwork(); + + // This logic is thightly couploed to how `DcpExecutor` allocates endpoints + var annotation = new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "blah", name: "http"); + annotation.AllocatedEndpoint = new(annotation, "localhost", port); + destination.Annotations.Add(annotation); + + (string containerHost, int containerPort) = destination.IsContainer() + ? ("destination.dev.internal", targetPort) + : ("host.docker.internal", port); + + var containerEndpoint = new AllocatedEndpoint(annotation, containerHost, containerPort, EndpointBindingMode.SingleAddress, targetPortExpression: targetPort.ToString(), KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(containerEndpoint); + annotation.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + + var expression = destination.GetEndpoint(annotation.Name).Property(property); + + var resultFromCaller = await expression.GetValueAsync(new ValueProviderContext + { + Caller = source + }); + Assert.Equal(expectedResult, resultFromCaller); + + var resultFromNetwork = await expression.GetValueAsync(new ValueProviderContext + { + Network = network + }); + Assert.Equal(expectedResult, resultFromNetwork); + + static IResourceWithEndpoints CreateResource(string name, ResourceKind kind) + { + if (kind == ResourceKind.Container) + { + var resource = new TestResource(name); + resource.Annotations.Add(new ContainerImageAnnotation { Image = "test-image" }); + return resource; + } + else + { + return new TestResource(name); + } + } + } + + public enum ResourceKind + { + Host, + Container + } + private sealed class TestResource(string name) : Resource(name), IResourceWithEndpoints { } diff --git a/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs b/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs index 88bbcdd48fd..429757d98a8 100644 --- a/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs +++ b/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs @@ -84,6 +84,10 @@ public async Task ExpressionResolverGeneratesCorrectEndpointStrings(string exprN { var builder = DistributedApplication.CreateBuilder(); + var containerHost = targetIsContainer + ? "testresource.dev.internal" + : KnownHostNames.DefaultContainerTunnelHostName; + var target = builder.AddResource(new TestExpressionResolverResource(exprName)) .WithEndpoint("endpoint1", e => { @@ -92,31 +96,31 @@ public async Task ExpressionResolverGeneratesCorrectEndpointStrings(string exprN if (sourceIsContainer) { // Note: on the container network side the port and target port are always the same for AllocatedEndpoint. - var ae = new AllocatedEndpoint(e, KnownHostNames.DefaultContainerTunnelHostName, 22345, EndpointBindingMode.SingleAddress, targetPortExpression: "22345", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var ae = new AllocatedEndpoint(e, containerHost, 22345, EndpointBindingMode.SingleAddress, targetPortExpression: "22345", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); var snapshot = new ValueSnapshot(); snapshot.SetValue(ae); e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); } }) .WithEndpoint("endpoint2", e => - { - e.UriScheme = "https"; - e.AllocatedEndpoint = new(e, "localhost", 12346, targetPortExpression: "10001"); - if (sourceIsContainer) - { - var ae = new AllocatedEndpoint(e, KnownHostNames.DefaultContainerTunnelHostName, 22346, EndpointBindingMode.SingleAddress, targetPortExpression: "22346", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); - var snapshot = new ValueSnapshot(); - snapshot.SetValue(ae); - e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); - } - }) + { + e.UriScheme = "https"; + e.AllocatedEndpoint = new(e, "localhost", 12346, targetPortExpression: "10001"); + if (sourceIsContainer) + { + var ae = new AllocatedEndpoint(e, containerHost, 22346, EndpointBindingMode.SingleAddress, targetPortExpression: "22346", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(ae); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + } + }) .WithEndpoint("endpoint3", e => { e.UriScheme = "https"; e.AllocatedEndpoint = new(e, "host with space", 12347); if (sourceIsContainer) { - var ae = new AllocatedEndpoint(e, KnownHostNames.DefaultContainerTunnelHostName, 22347, EndpointBindingMode.SingleAddress, targetPortExpression: "22346", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var ae = new AllocatedEndpoint(e, containerHost, 22347, EndpointBindingMode.SingleAddress, targetPortExpression: "22346", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); var snapshot = new ValueSnapshot(); snapshot.SetValue(ae); e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); @@ -217,10 +221,18 @@ public async Task ContainerToContainerEndpointShouldResolve() { var builder = DistributedApplication.CreateBuilder(); + var endpoint = new EndpointAnnotation(System.Net.Sockets.ProtocolType.Tcp, KnownNetworkIdentifiers.DefaultAspireContainerNetwork) + { + Name = "http", + UriScheme = "http", + Port = 8001, + TargetPort = 8080, + }; + endpoint.AllocatedEndpoint = new(endpoint, "myContainer.dev.internal", (int)endpoint.TargetPort, EndpointBindingMode.SingleAddress, "{{ targetPort }}"); + var connectionStringResource = builder.AddResource(new MyContainerResource("myContainer")) .WithImage("redis") - .WithHttpEndpoint(port: 8001, targetPort: 8080) - .WithEndpoint("http", ep => ep.AllocatedEndpoint = new(ep, "localhost", 8001, EndpointBindingMode.SingleAddress, "{{ targetPort }}", KnownNetworkIdentifiers.LocalhostNetwork)); + .WithAnnotation(endpoint); var dep = builder.AddContainer("container", "redis") .WithReference(connectionStringResource) From 6be22deb8eb0c39ac2902d6ecdbfe86094e97429 Mon Sep 17 00:00:00 2001 From: afscrome Date: Sun, 1 Feb 2026 23:46:11 +0000 Subject: [PATCH 2/7] PR Review + fix broken test. --- .../Aspire.Hosting.Containers.Tests/ContainerResourceTests.cs | 4 ++-- tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs | 2 +- tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Aspire.Hosting.Containers.Tests/ContainerResourceTests.cs b/tests/Aspire.Hosting.Containers.Tests/ContainerResourceTests.cs index 335bbcac08b..06495623fc2 100644 --- a/tests/Aspire.Hosting.Containers.Tests/ContainerResourceTests.cs +++ b/tests/Aspire.Hosting.Containers.Tests/ContainerResourceTests.cs @@ -102,7 +102,7 @@ public async Task AddContainerWithArgs() e.AllocatedEndpoint = new(e, "localhost", 1234, targetPortExpression: "1234"); // For container-container lookup we need to add an AllocatedEndpoint on the container network side - var ccae = new AllocatedEndpoint(e, KnownHostNames.DefaultContainerTunnelHostName, 2234, EndpointBindingMode.SingleAddress, targetPortExpression: "2234", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var ccae = new AllocatedEndpoint(e, "c1.dev.internal", 2234, EndpointBindingMode.SingleAddress, targetPortExpression: "2234", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); var snapshot = new ValueSnapshot(); snapshot.SetValue(ccae); e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); @@ -114,7 +114,7 @@ public async Task AddContainerWithArgs() e.UriScheme = "http"; // We only care about the container-side endpoint for this test var snapshot = new ValueSnapshot(); - var ae = new AllocatedEndpoint(e, "localhost", 5678, EndpointBindingMode.SingleAddress, targetPortExpression: "5678", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var ae = new AllocatedEndpoint(e, "container.dev.internal", 5678, EndpointBindingMode.SingleAddress, targetPortExpression: "5678", KnownNetworkIdentifiers.DefaultAspireContainerNetwork); snapshot.SetValue(ae); e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); }) diff --git a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs index e1527505eb4..330b1aece37 100644 --- a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs +++ b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs @@ -2180,7 +2180,7 @@ public async Task ProjectExecutable_NoSupportsDebuggingAnnotation_RunsInProcessM [InlineData(false, null, "host.docker.internal")] [InlineData(true, "super.star", "aspire.dev.internal")] [InlineData(false, "mega.mushroom", "mega.mushroom")] - public async Task EndpointsAllocatedCorrectly2(bool useTunnel, string? containerHostName, string expectedContainerHost) + public async Task EndpointsAllocatedCorrectly(bool useTunnel, string? containerHostName, string expectedContainerHost) { var builder = DistributedApplication.CreateBuilder(); var executable = builder.AddExecutable("anExecutable", "command", "") diff --git a/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs b/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs index 31eae6e0cf1..11e3e3d7de6 100644 --- a/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs +++ b/tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs @@ -320,7 +320,7 @@ public async Task PropertyResolutionTest(EndpointProperty property, ResourceKind var network = source.GetDefaultResourceNetwork(); - // This logic is thightly couploed to how `DcpExecutor` allocates endpoints + // This logic is tightly coupled to how `DcpExecutor` allocates endpoints var annotation = new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "blah", name: "http"); annotation.AllocatedEndpoint = new(annotation, "localhost", port); destination.Annotations.Add(annotation); From 37eaf829264200bb47cc46e3395eaf8badd73199 Mon Sep 17 00:00:00 2001 From: afscrome Date: Mon, 2 Feb 2026 00:19:13 +0000 Subject: [PATCH 3/7] Fix `WithEnvironmentTests.EnvironmentVariableExpressions()` --- tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs index dd40af66a63..c6b9b0a1070 100644 --- a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs +++ b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs @@ -227,7 +227,12 @@ public async Task EnvironmentVariableExpressions() .WithHttpEndpoint(name: "primary", targetPort: 10005) .WithEndpoint("primary", ep => { - ep.AllocatedEndpoint = new AllocatedEndpoint(ep, "localhost", 90); + ep.AllocatedEndpoint = new AllocatedEndpoint(ep, "localhost", 17454); + + var ae = new AllocatedEndpoint(ep, "container1.dev.internal", 10005, EndpointBindingMode.SingleAddress, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(ae); + ep.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); }); var endpoint = container.GetEndpoint("primary"); From a7858d4be37a32e8f8653b98f7d34fa6eee1893a Mon Sep 17 00:00:00 2001 From: afscrome Date: Mon, 2 Feb 2026 20:33:45 +0000 Subject: [PATCH 4/7] - Fix Broken Tests - Add some DebuggerDisplay attributes to `ValueSnapshot`, and `NetworkEndpointSnapshotList` to make debugging easier - Explcitly use `*.dev.internal` alias for container networks - Don't allocate endpoints on custom networks --- .../ApplicationModel/EndpointAnnotation.cs | 2 ++ .../ApplicationModel/ValueSnapshot.cs | 4 ++++ src/Aspire.Hosting/Dcp/DcpExecutor.cs | 17 +++++++++-------- .../AzurePostgresExtensionsTests.cs | 8 +++++++- .../AddMilvusTests.cs | 8 +++++++- .../PostgresMcpBuilderTests.cs | 8 +++++++- .../AddQdrantTests.cs | 16 ++++++++++++++-- .../Aspire.Hosting.Redis.Tests/AddRedisTests.cs | 8 +++++++- 8 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs b/src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs index a4009d690bc..8ee659e3040 100644 --- a/src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs +++ b/src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs @@ -244,6 +244,7 @@ public AllocatedEndpoint? AllocatedEndpoint /// /// AllocatedEndpoint snapshot /// The ID of the network that is associated with the AllocatedEndpoint snapshot. +[DebuggerDisplay("NetworkID = {NetworkID}, Endpoint = {Snapshot}")] public record class NetworkEndpointSnapshot(ValueSnapshot Snapshot, NetworkIdentifier NetworkID); /// @@ -251,6 +252,7 @@ public record class NetworkEndpointSnapshot(ValueSnapshot Sna /// public class NetworkEndpointSnapshotList : IEnumerable { + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] private readonly ConcurrentBag _snapshots = new(); /// diff --git a/src/Aspire.Hosting/ApplicationModel/ValueSnapshot.cs b/src/Aspire.Hosting/ApplicationModel/ValueSnapshot.cs index 47081560cfe..003137933e9 100644 --- a/src/Aspire.Hosting/ApplicationModel/ValueSnapshot.cs +++ b/src/Aspire.Hosting/ApplicationModel/ValueSnapshot.cs @@ -1,6 +1,8 @@ // 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; + namespace Aspire.Hosting.ApplicationModel; /// @@ -12,6 +14,7 @@ namespace Aspire.Hosting.ApplicationModel; /// /// Thread-safe for concurrent SetValue / SetException / GetValueAsync calls. /// +[DebuggerDisplay("{Value= {DebuggerValue()}")] public sealed class ValueSnapshot where T : notnull { private readonly TaskCompletionSource _firstValueTcs = @@ -73,4 +76,5 @@ public void SetException(Exception exception) } } } + private T? DebuggerValue() => IsValueSet ? _firstValueTcs.Task.Result : default; } diff --git a/src/Aspire.Hosting/Dcp/DcpExecutor.cs b/src/Aspire.Hosting/Dcp/DcpExecutor.cs index c5a064b6334..df379b2f253 100644 --- a/src/Aspire.Hosting/Dcp/DcpExecutor.cs +++ b/src/Aspire.Hosting/Dcp/DcpExecutor.cs @@ -980,23 +980,24 @@ private void AddAllocatedEndpointInfo(IEnumerable resourc if (appResource.DcpResource is Container ctr && ctr.Spec.Networks is not null) { - foreach (var network in ctr.Spec.Networks) + // Once container networks are fully supported, this should allocate endpoints on those networks + var containerNetwork = ctr.Spec.Networks.FirstOrDefault(n => n.Name == KnownNetworkIdentifiers.DefaultAspireContainerNetwork.Value); + + if (containerNetwork is not null) { - var networkID = new NetworkIdentifier(network.Name!); - var address = network.Aliases!.Last(); // relying on an implementation detail here to ensure we get the `*.dev.internal` alias var port = sp.EndpointAnnotation.TargetPort!; - var tunnelAllocatedEndpoint = new AllocatedEndpoint( + var allocatedEndpoint = new AllocatedEndpoint( sp.EndpointAnnotation, - address, + $"{sp.ModelResource.Name}.dev.internal", (int)port, EndpointBindingMode.SingleAddress, targetPortExpression: $$$"""{{- portForServing "{{{svc.Metadata.Name}}}" -}}""", - networkID + KnownNetworkIdentifiers.DefaultAspireContainerNetwork ); var snapshot = new ValueSnapshot(); - snapshot.SetValue(tunnelAllocatedEndpoint); - sp.EndpointAnnotation.AllAllocatedEndpoints.TryAdd(networkID, snapshot); + snapshot.SetValue(allocatedEndpoint); + sp.EndpointAnnotation.AllAllocatedEndpoints.TryAdd(allocatedEndpoint.NetworkID, snapshot); } } } diff --git a/tests/Aspire.Hosting.Azure.Tests/AzurePostgresExtensionsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzurePostgresExtensionsTests.cs index 53fe1bb9528..a7f55cc7a7a 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzurePostgresExtensionsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzurePostgresExtensionsTests.cs @@ -368,7 +368,13 @@ public async Task WithPostgresMcpOnAzureDatabaseRunAsContainerAddsMcpResource() .WithPasswordAuthentication(userName: user, password: pass) .RunAsContainer(c => { - c.WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5432)); + c.WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5432); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "postgres.dev.internal", 5432, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); }); var db = postgres.AddDatabase("db") diff --git a/tests/Aspire.Hosting.Milvus.Tests/AddMilvusTests.cs b/tests/Aspire.Hosting.Milvus.Tests/AddMilvusTests.cs index 474e5458d2c..433b15b1a46 100644 --- a/tests/Aspire.Hosting.Milvus.Tests/AddMilvusTests.cs +++ b/tests/Aspire.Hosting.Milvus.Tests/AddMilvusTests.cs @@ -96,7 +96,13 @@ public async Task MilvusClientAppWithReferenceContainsConnectionStrings() var pass = appBuilder.AddParameter("apikey", "pass"); var milvus = appBuilder.AddMilvus("my-milvus", pass) - .WithEndpoint("grpc", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", MilvusPortGrpc)); + .WithEndpoint("grpc", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", MilvusPortGrpc); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "my-milvus.dev.internal", MilvusPortGrpc, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); var projectA = appBuilder.AddProject("projecta", o => o.ExcludeLaunchProfile = true) .WithReference(milvus); diff --git a/tests/Aspire.Hosting.PostgreSQL.Tests/PostgresMcpBuilderTests.cs b/tests/Aspire.Hosting.PostgreSQL.Tests/PostgresMcpBuilderTests.cs index 42272057861..e2eb3b0de6d 100644 --- a/tests/Aspire.Hosting.PostgreSQL.Tests/PostgresMcpBuilderTests.cs +++ b/tests/Aspire.Hosting.PostgreSQL.Tests/PostgresMcpBuilderTests.cs @@ -75,7 +75,13 @@ public async Task WithPostgresMcpOnDatabaseSetsDatabaseUriEnvironmentVariable() var pass = appBuilder.AddParameter("pass", "p@ssw0rd1"); appBuilder.AddPostgres("postgres", password: pass) - .WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5432)) + .WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5432); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "postgres.dev.internal", 5432, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }) .AddDatabase("db") .WithPostgresMcp(); diff --git a/tests/Aspire.Hosting.Qdrant.Tests/AddQdrantTests.cs b/tests/Aspire.Hosting.Qdrant.Tests/AddQdrantTests.cs index c9d2a819290..4d50b6207c1 100644 --- a/tests/Aspire.Hosting.Qdrant.Tests/AddQdrantTests.cs +++ b/tests/Aspire.Hosting.Qdrant.Tests/AddQdrantTests.cs @@ -169,8 +169,20 @@ public async Task QdrantClientAppWithReferenceContainsConnectionStrings() var pass = appBuilder.AddParameter("pass", "pass"); var qdrant = appBuilder.AddQdrant("my-qdrant", pass) - .WithEndpoint("grpc", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6334)) - .WithEndpoint("http", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6333)); + .WithEndpoint("grpc", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6334); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "my-qdrant.dev.internal", 6334, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }) + .WithEndpoint("http", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6333); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "my-qdrant.dev.internal", 6333, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); var projectA = appBuilder.AddProject("projecta", o => o.ExcludeLaunchProfile = true) .WithReference(qdrant); diff --git a/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs b/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs index 362b9079ea7..8feca671a4b 100644 --- a/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs +++ b/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs @@ -713,7 +713,13 @@ public async Task RedisInsightEnvironmentCallbackIsIdempotent() using var appBuilder = TestDistributedApplicationBuilder.CreateWithTestContainerRegistry(testOutputHelper); var redis = appBuilder.AddRedis("redis") - .WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6379)) + .WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 6379); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "redis.dev.internal", 6379, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }) .WithRedisInsight(); using var app = appBuilder.Build(); From 6168b2a70916578ec729a7e3bdf8e5dcd8b04a3e Mon Sep 17 00:00:00 2001 From: afscrome Date: Tue, 3 Feb 2026 00:14:25 +0000 Subject: [PATCH 5/7] Fix test changed by previous commit removing support for custom networks. --- tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs index 330b1aece37..70f8deea224 100644 --- a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs +++ b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs @@ -2254,8 +2254,8 @@ async ValueTask AssertTunneledPort(IResourceWithEndpoints resource, string endpo await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 28765); //TODO: Not sure if this is the desired behaviour - await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, "custom.alias", 21234); - await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, "custom.alias", 28765); + await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{containerWithAlias.Resource.Name}.dev.internal", 21234); + await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{containerWithAlias.Resource.Name}.dev.internal", 28765); async ValueTask AssertEndpoint(IResourceWithEndpoints resource, string name, NetworkIdentifier network, string address, int port) { From 9b3ab100b7247c3d7e97b0e7e751789d4020a473 Mon Sep 17 00:00:00 2001 From: afscrome Date: Tue, 3 Feb 2026 00:35:40 +0000 Subject: [PATCH 6/7] One more failing test --- .../AddRedisTests.cs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs b/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs index 8feca671a4b..cace9589d26 100644 --- a/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs +++ b/tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs @@ -301,8 +301,27 @@ public async Task WithRedisInsightProducesCorrectEnvironmentVariables() using var app = builder.Build(); // Add fake allocated endpoints. - redis1.WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5001)); - redis2.WithEndpoint("tcp", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5002)); + redis1.WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5001); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "myredis1.dev.internal", 5001, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); + redis2.WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5002); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "myredis2.dev.internal", 5002, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); + redis3.WithEndpoint("tcp", e => + { + e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 5003); + var snapshot = new ValueSnapshot(); + snapshot.SetValue(new AllocatedEndpoint(e, "myredis3.dev.internal", 5003, EndpointBindingMode.SingleAddress, targetPortExpression: null, networkID: KnownNetworkIdentifiers.DefaultAspireContainerNetwork)); + e.AllAllocatedEndpoints.TryAdd(KnownNetworkIdentifiers.DefaultAspireContainerNetwork, snapshot); + }); var redisInsight = Assert.Single(builder.Resources.OfType()); var envs = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(redisInsight); @@ -367,7 +386,6 @@ public async Task WithRedisInsightProducesCorrectEnvironmentVariables() Assert.Equal("RI_REDIS_ALIAS3", item.Key); Assert.Equal(redis3.Resource.Name, item.Value); }); - } [Fact] From fb7c0654f865f987a9e80b152c643dc7a57b1a3e Mon Sep 17 00:00:00 2001 From: afscrome Date: Tue, 3 Feb 2026 18:10:54 +0000 Subject: [PATCH 7/7] Remove redundant comment. --- tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs index 70f8deea224..8ccc1004794 100644 --- a/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs +++ b/tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs @@ -2253,7 +2253,6 @@ async ValueTask AssertTunneledPort(IResourceWithEndpoints resource, string endpo await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 25678); await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.LocalhostNetwork, KnownHostNames.Localhost, 28765); - //TODO: Not sure if this is the desired behaviour await AssertEndpoint(containerWithAlias.Resource, "proxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{containerWithAlias.Resource.Name}.dev.internal", 21234); await AssertEndpoint(containerWithAlias.Resource, "notProxied", KnownNetworkIdentifiers.DefaultAspireContainerNetwork, $"{containerWithAlias.Resource.Name}.dev.internal", 28765);