aspire icon indicating copy to clipboard operation
aspire copied to clipboard

"could not start the proxy for the service: listen tcp [::1]:80" when endpoint configuration is located in launchSettings.json

Open pacyfist opened this issue 1 year ago • 1 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

I have recently upgraded to <PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.1" /> and configuration of my microservices that was working fine is now currently incorrectly recognized by aspire causing this error on startup:

 Aspire.Hosting.Dcp.dcpctrl.ServiceReconciler[0]
      could not start the proxy {"ServiceName": {"name":"second-service"}, "Reconciliation": 4, "error": "could not start the proxy for the service: listen tcp [::1]:80: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted."}

I use several launch profiles to configure how the microservices should be configured so the entire configuration is located in launchSettings.json files.

builder
    .AddProject<Projects.FirstServiceExample>(
        name: "first-service",
        launchProfileName: "firstService");

builder
    .AddProject<Projects.SecondServiceExample>(
        name: "second-service",
        launchProfileName: "secondService");

This is one of the launchSettings.json files:

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "firstService": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "UseDevEnvironment": "true",
        "Kestrel:Endpoints:Http:Url": "http://*:1338"
      }
    }
  },
  (...)
}

and I keep my appsettings.json clean to be used when creating containers.

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://*:80"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

This code Unfortunately in this version there is a bug that ignores environment variables when setting up kestrel endpoints this way.

    private static IConfiguration GetConfiguration(ProjectResource projectResource)
    {
        var projectMetadata = projectResource.GetProjectMetadata();

        // For testing
        if (projectMetadata.Configuration is { } configuration)
        {
            return configuration;
        }

        var projectDirectoryPath = Path.GetDirectoryName(projectMetadata.ProjectPath)!;
        var appSettingsPath = Path.Combine(projectDirectoryPath, "appsettings.json");
        var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
        var appSettingsEnvironmentPath = Path.Combine(projectDirectoryPath, $"appsettings.{env}.json");

        var configBuilder = new ConfigurationBuilder();
        configBuilder.AddJsonFile(appSettingsPath, optional: true);
        configBuilder.AddJsonFile(appSettingsEnvironmentPath, optional: true);
        return configBuilder.Build();
    }

configuration is only accepted from appSettings.json and never from environment variables in launchSettings.json causing all microservices to try to use port 80.

I see that this code was reworked, but there still is a similar problem on the latest code in github. This will not work correctly when someone uses launchSettings.json to change kestrel configuration:

    private static bool IsKestrelHttp2ConfigurationPresent(ProjectResource projectResource)
    {
        var projectMetadata = projectResource.GetProjectMetadata();

        var projectDirectoryPath = Path.GetDirectoryName(projectMetadata.ProjectPath)!;
        var appSettingsPath = Path.Combine(projectDirectoryPath, "appsettings.json");
        var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
        var appSettingsEnvironmentPath = Path.Combine(projectDirectoryPath, $"appsettings.{env}.json");

        var configBuilder = new ConfigurationBuilder();
        configBuilder.AddJsonFile(appSettingsPath, optional: true);
        configBuilder.AddJsonFile(appSettingsEnvironmentPath, optional: true);
        var config = configBuilder.Build();
        var protocol = config["Kestrel:EndpointDefaults:Protocols"];
        return protocol == "Http2";
    }

Expected Behavior

configuration from "environmentVariables" in launchSettings.json should be understood and used when launching projects using Aspire. My second microservice should open an endpoint on 1338 port instead of 80

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version info

.NET SDK: Version: 9.0.100-rc.1.24452.12 Commit: 81a714c6d3 Workload version: 9.0.100-manifests.977c08b4 MSBuild version: 17.12.0-preview-24422-09+d17ec720d

Anything else?

No response

pacyfist avatar Oct 04 '24 10:10 pacyfist

We don’t discover endpoints for resources based on environment variables. If you want to override the settings you can use the WithEndpoint overload that takes a callback and setup the binding information based on your conventions.

davidfowl avatar Oct 04 '24 14:10 davidfowl

I'm reporting this as a bug, because my configuration worked perfectly in 8.0.2 and it broke only now now after update to 8.2.1. You say that my only choice it to keep and maintain a duplicate of my configuration inside Program.cs of aspire orchestrator? I find the approach of ignoring env variables severely limiting.

pacyfist avatar Oct 07 '24 08:10 pacyfist

8.1 added support for reading kestrel configuration, you can disable this by passing options to AddProject to tell it to avoid parsing the configuration. Setting endpoint configuration outside of the appmodel means it can't correctly understand what points are bound nor what address are valid to give to clients.

You should be able to do this to get back to 8.0 behavior:

builder
    .AddProject<Projects.AspireApp39_ApiService>(
        name: "second-service",
        o =>
        {
            o.LaunchProfileName = "secondService";
            o.ExcludeKestrelEndpoints = true;
        });

davidfowl avatar Oct 07 '24 08:10 davidfowl

This was an international breaking change. We'll make sure to get it documented.

davidfowl avatar Jan 14 '25 08:01 davidfowl