microsoft / microsoft/aspire

Allow better modeling of external endpoints to enable resources to reference each other's non-external vs. external endpoints

Open
#2,658 7 comments 2 reactions 0 assignees View on GitHub
area-app-model
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

As part of building out the [HealthChecksUI sample](https://github.com/dotnet/aspire-samples/pull/140) and the addition of the `EndpointAnnotation.IsExternal` flag in preview.5, it's become clear we need to improve how we model a resource's endpoints such that another resource can explicitly reference its internal or external endpoint in cases where they differ.

In short, we should ensure that external endpoints are explicitly modeled in a consistent manner and our default experiences for resources result in discrete external endpoints being modeled (in addition to the default endpoints) when that resource is marked as external.

Strawman for proposed changes:

- Add a new `AsExternal()` extension method to `IResourceBuilder where T : IResourceWithEndpoints` that creates copies of all the resource's non-external endpoints but marked as external and named for the original endpoint but with a `-external` suffix. This can be used to easily expose external endpoints for any resource, e.g.:

```csharp
builder.AddProject("frontend")
.WithReference(basketService)
.WithReference(catalogService)
.AsExternal();
```

Assuming an ASP.NET Core project has a launch profile `"https"` with two endpoints defined in its `"applicationUrl"` property (one for https, one for http), and the AppHost project was launched using a launch profile named `"https"`, the above would result in **four** endpoints being modeled for the project:

1. "https": `IsExternal = false`
2. "http": `IsExternal = false`
3. "https-external": `IsExternal = true`
4. "http-external": `IsExternal = true`

- Update the `Dcp.ApplicationExecutor` such that resource endpoints with `IsExternal` and `IsProxied` set to `true` result in DCP launching the proxy configured to listen on the additional port for that "external" endpoint, but resolve to the usual target port for the application instance(s), i.e. the proxy terminates all endpoints marked as `IsExternal` and forwards them to the application instance(s) listen port(s).
- Update the `Dcp.ApplicationExecutor` such that the logic for injecting the endpoint port into the application instance(s) is based on whether the `EnivonrmentVariable` property on the endpoint is set and some way for the resource to specialize how the value should be written to the variable. The default would be to group endpoint ports into a semi-colon delimited string for each environment variable specified but the `ProjectResource` would implement the hook (interface or annotation) to specify it wants the full endpoint URL written via a semi-colon delimited list if the environment variable is `ASPNETCORE_URLS`. The goal here is to remove all the custom logic in `ApplicationExecutor` for how the endpoint details are written into the environment variables.
- Consider updating `EndpointReference` and adding convenience methods to allow easily retrieving the desired external endpoint for a resource, e.g. `GetExternalEndpoint(string name)` which will look for an endpoint where `(Name == name || Name == `$"{name}-external") && IsExternal == true`.
- ❓ Should there be a concept of getting the "default" endpoint so that I can simply ask for a resource's default endpoint without needing to know its name? Maybe just `GetExternalEndpoints()` and `GetEndpoints()` that returns an `IEnumerable` would be enough, along with `WithReference(IEnumerable endpoints)`, then one could do `.WithReference(frontend.GetExternalEndpoints())`
- Update `WithReference(IResourceBuilder resource)` to use only the non-external endpoints of the passed resource. Resources wishing to reference another resource's external endpoint will need to pass the `EndpointReference` of the external endpoint explicitly (see suggestion for `GeExternalndpoint` above), e.g.:

```csharp
builder.AddProject("frontend")
.WithReference(basketService)
.WithReference(catalogService)
.AsExternal();

builder.AddAvailabilityChecker("availabilitychecker")
.WithReference(frontend.GetExternalEndpoint("http")); // See point above about whether we should introduce concept of "default" endpoint so names don't have to be hard-coded like this
```
- ❓ Are any updates to manifest writing for endpoints needed (and by extension AZD)? e.g. how to make AZD understand that a reference to `{frontend.bindings.http-external.url}` means the externally resolvable FQDN assigned by ACA needs to be used?
- I hit a couple of issues in AZD when building out the sample:
- When trying to set the environment variable of a resource to just the `host` portion of another resource's endpoint, e.g. the manifest contained `"env": { "AllowedHosts": "{apiservice.bindings.http.host};{apiservice.bindings.https.host}" ... `, this resulted in the environment variable being set to just `"apiservice;apiservice"` rather than the full internal hostname from the binding URL.
- For a container resource that had environment variable expressions that referenced other resources, it looked like AZD's own yaml templating syntax was being written into the `resources.bicep` file that's used to deploy the container resource, which resulted in that expression not being processed and just being directly to the ACA app environment variables config.

Related #2099

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.