Skip to content

Conversation

@sebastienros
Copy link
Member

@sebastienros sebastienros commented Oct 18, 2025

Description

  • Generates polyglot-friendly service endpoint environment variables like WEATHERAPI, WEATHERAPI_HTTPS
  • Adds the ability to set the name of the service in ENVS
  • Buids upon the newly added ReferenceEnvironmentInjectionAnnotation to allow the customization per resource or per resource type which should get Service Discovery endpoints or simple ones.

Fixes #12069

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

@github-actions
Copy link
Contributor

github-actions bot commented Oct 18, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12141

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12141"

@sebastienros sebastienros force-pushed the sebros/polyglotservices branch from 368ccc6 to 41399a4 Compare October 18, 2025 00:34
@sebastienros sebastienros requested a review from eerhardt October 18, 2025 00:45
@sebastienros sebastienros force-pushed the sebros/polyglotservices branch from a269804 to 5863688 Compare October 18, 2025 18:07

### Experiencing the app

Before starting the app host run `npm install` in each javascript folder.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there not calls to .WithNpmPackageInstallation in the AppHost?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, didn't know about it then Damian told me. Should I add it in this PR? @IEvangelist note that the Vite sample doesn't work at all, issues with authenticating on npm, not sure if the extension method will take care of this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, dont' add it to this PR.

@davidfowl
Copy link
Member

This approach looks solid. Since we're not trying to do any fancy service discovery, it's a very simple name based scheme.

@sebastienros sebastienros marked this pull request as ready for review October 18, 2025 23:17
Copilot AI review requested due to automatic review settings October 18, 2025 23:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces simplified service URL environment variable format that is more polyglot-friendly. It adds the ability to generate environment variables in the format {RESOURCENAME}_{ENDPOINT} (e.g., WEATHERAPI_HTTPS) alongside the existing .NET service discovery format.

Key changes:

  • Expands ReferenceEnvironmentInjectionFlags enum to support new endpoint injection patterns
  • Updates environment variable generation logic to emit both service discovery and simplified endpoint formats
  • Modernizes existing playground JavaScript applications to use the new simplified format

Reviewed Changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Aspire.Hosting/ApplicationModel/ReferenceEnvironmentInjectionFlags.cs Adds new flags for ServiceDiscovery and Endpoints injection
src/Aspire.Hosting/ResourceBuilderExtensions.cs Updates environment variable generation to support both formats and renames method
src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs Updates dev tunnel references to use new injection patterns
tests/Aspire.Hosting.Tests/WithReferenceTests.cs Adds tests for new simplified environment variable format
playground/AspireWithJavaScript/* Updates JavaScript applications to use simplified environment variables
Various test snapshots Updates expected output to include new environment variable format

@davidfowl
Copy link
Member

Update this template

target: process.env.services__apiservice__https__0 || process.env.services__apiservice__http__0,

@davidfowl
Copy link
Member

Dev tunnels as a custom WithReference method that should be updated.

@sebastienros
Copy link
Member Author

Dev tunnels as a custom WithReference method that should be updated.

I thought I did, or did I miss another one?

Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@sebastienros
Copy link
Member Author

Simingly unrelated tests are failing on macos now, tried 3 times. These work locally on macos though:

Test summary: total: 38, failed: 0, succeeded: 38, skipped: 0, duration: 2.1s
Build succeeded in 4.3s
➜  Aspire.Hosting.Tests git:(sebros/polyglotservices) dotnet test -- --filter-method="*DistributedApplicationPipelineTests*"

@davidfowl
Copy link
Member

Those are my bugs #12160, there are still more to delete.

/// Specifies which connection or endpoint information should be injected into environment variables when <c>WithReference()</c> is invoked.
/// </summary>
[Flags]
public enum ReferenceEnvironmentInjectionFlags
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can follow up on naming.

/// <summary>
/// Each endpoint defined on the resource will be injected using the format "{RESOURCENAME}_{ENDPOINTNAME}".
/// </summary>
Endpoints = 1 << 3,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure Endpoints is the right name here. Maybe SimplifiedEndpoints? or SimpleEndpoints?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow up API review, I think this whole enum is unclear.

/// Each endpoint defined on the resource will be injected using the format "services__{resourceName}__{endpointName}__{endpointIndex}".
/// </summary>
All = ConnectionString | ConnectionProperties
ServiceDiscovery = 1 << 2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ServiceDiscovery enough in this context? Is it really .NET ServiceDiscovery? Even using the Endpoints format is still "service discovery", right? Just not the Microsoft.Extensions.ServiceDiscovery format.


/// <summary>
/// Both connection string and connection properties will be injected as environment variables.
/// Each endpoint defined on the resource will be injected using the format "services__{resourceName}__{endpointName}__{endpointIndex}".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endpointIndex

What is the reason we have an index at the end? How are those scenarios going to work with the Endpoints format?

Copy link
Member

@davidfowl davidfowl Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need index because each endpoint gets a single env variable. The service discovery format has a one to many relationship with endpoints. You can have 5 endpoints named differently with an http scheme and use the resource name (e.g. http://foo to refer to it). That will load balance across those 5 addresses at runtime.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can have 5 endpoints named differently with an http scheme and use the resource name (e.g. http://foo/ to refer to it). That will load balance across those 5 addresses at runtime.

In that case is endpointName correct above? Or is it uri.scheme?

If you have 5 endpoints named differently, why isn't services__{resourceName}__{endpointName} enough?

Copy link
Member

@davidfowl davidfowl Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service discovery implementation relies on IConfiguration and that is how you represent arrays:

{
    "services": {
        "foo":  [
            "http://locahost:5006",
            "http://locahost:5002"
            "http://locahost:5004"  
        ]
   }
}

"services__foo__http__0" The system does some munging to support different configuration formats but they are all ugly to support this model.

cc @ReubenBond

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and that is how you represent arrays

But in this new format, we aren't going to support arrays?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't any ENV defined by aspire that is not __0. We only have it because it's an array, but always use a single value right now. So for the new ENV there is no reason to have it used at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. We don't need it here.

builder.WithEnvironment(envVarName, uri.ToString());
if (flags.HasFlag(ReferenceEnvironmentInjectionFlags.Endpoints))
{
var envVarName = $"{externalService.Resource.Name.ToUpperInvariant()}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need the uri.Scheme in it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only added these if it was necessary to discriminate from other resources. Here the resource is ExternalServiceResource and has a single scheme, so there could only be a conflict if the same resource was also referenced using another interface WithReference call. And in these cases the endpoint name will be used as a discriminator. So I think it's safe to not include it here.

// In publish mode we can't read the parameter value to get the scheme so use 'default'
envVarName = $"services__{externalService.Resource.Name}__default__0";
discoveryEnvVarName = $"services__{externalService.Resource.Name}__default__0";
endpointEnvVarName = externalService.Resource.Name.ToUpperInvariant();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need _default in it?

Also, how is someone supposed to code against this scenario where it changes from uri.Schema to default after publish?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand why we need the scheme at all. We just need to decide if we should have another prefix for external services so they don't collide (though resource names are unique).

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Except one fat fingers.

@sebastienros sebastienros enabled auto-merge (squash) October 20, 2025 19:30
@sebastienros sebastienros merged commit 6a43c5e into main Oct 20, 2025
1176 of 1187 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the 13.0 milestone Oct 20, 2025
@sebastienros sebastienros deleted the sebros/polyglotservices branch October 20, 2025 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Model service connections like connection properties

5 participants