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
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ private static IResourceBuilder<AzureCosmosDBResource> RunAsEmulator(this IResou
if (useVNextPreview)
{
builder.WithHttpEndpoint(name: EmulatorHealthEndpointName, targetPort: 8080)
.WithEndpoint(EmulatorHealthEndpointName, e => e.ExcludeReferenceEndpoint = true)
.WithHttpHealthCheck(endpointName: EmulatorHealthEndpointName, path: "/ready")
.WithUrlForEndpoint(EmulatorHealthEndpointName, u => u.DisplayLocation = UrlDisplayLocation.DetailsOnly);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ public static IResourceBuilder<AzureEventHubsResource> RunAsEmulator(this IResou
builder
.WithEndpoint(name: "emulator", targetPort: 5672)
.WithHttpEndpoint(name: EmulatorHealthEndpointName, targetPort: 5300)
.WithEndpoint(EmulatorHealthEndpointName, e => e.ExcludeReferenceEndpoint = true)
.WithHttpHealthCheck(endpointName: EmulatorHealthEndpointName, path: "/health")
.WithAnnotation(new ContainerImageAnnotation
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ public static IResourceBuilder<AzureServiceBusResource> RunAsEmulator(this IReso
builder
.WithEndpoint(name: "emulator", targetPort: 5672)
.WithHttpEndpoint(name: EmulatorHealthEndpointName, targetPort: 5300)
.WithEndpoint(EmulatorHealthEndpointName, e => e.ExcludeReferenceEndpoint = true)
.WithAnnotation(new ContainerImageAnnotation
{
Registry = ServiceBusEmulatorContainerImageTags.Registry,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public static IResourceBuilder<KeycloakResource> AddKeycloak(
.WithImageTag(KeycloakContainerImageTags.Tag)
.WithHttpEndpoint(port: port, targetPort: DefaultContainerPort)
.WithHttpEndpoint(targetPort: ManagementInterfaceContainerPort, name: ManagementEndpointName)
.WithEndpoint(ManagementEndpointName, e => e.ExcludeReferenceEndpoint = true)
.WithHttpHealthCheck(endpointName: ManagementEndpointName, path: "/health/ready")
.WithOtlpExporter()
.WithEnvironment(context =>
Expand Down
14 changes: 14 additions & 0 deletions src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,20 @@ public string Transport
/// <remarks>Defaults to <c>true</c>.</remarks>
public bool IsProxied { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether this endpoint is excluded from the default set when referencing the resource's endpoints
/// via <c>WithReference(resource)</c>. When <c>true</c>, the endpoint is excluded from the default set and must be
/// referenced explicitly using <c>WithReference(resource.GetEndpoint("name"))</c>.
/// </summary>
/// <remarks>
/// <para>Defaults to <c>false</c>.</para>
/// <para>
/// This is useful for resources that expose auxiliary endpoints (e.g., management dashboards, health check ports)
/// that should not be included in service discovery by default.
/// </para>
/// </remarks>
public bool ExcludeReferenceEndpoint { get; set; }

/// <summary>
/// Gets or sets a value indicating whether TLS is enabled for this endpoint.
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/Aspire.Hosting/ApplicationModel/EndpointReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ public sealed class EndpointReference : IManifestExpressionProvider, IValueProvi
/// </remarks>
public bool TlsEnabled => Exists && EndpointAnnotation.TlsEnabled;

/// <summary>
/// Gets a value indicating whether this endpoint is excluded from the default set when referencing the resource's endpoints.
/// </summary>
/// <remarks>
/// Returns <see langword="false"/> if the endpoint annotation has not been added to the resource yet.
/// Once the annotation exists, this property delegates to <see cref="EndpointAnnotation.ExcludeReferenceEndpoint"/>.
/// </remarks>
public bool ExcludeReferenceEndpoint => Exists && EndpointAnnotation.ExcludeReferenceEndpoint;

string IManifestExpressionProvider.ValueExpression => GetExpression();

/// <summary>
Expand Down
37 changes: 31 additions & 6 deletions src/Aspire.Hosting/ResourceBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,12 @@ private static Action<EnvironmentCallbackContext> CreateEndpointReferenceEnviron
}

var endpointName = endpoint.EndpointName;
if (!annotation.UseAllEndpoints && !annotation.EndpointNames.Contains(endpointName))
var isExplicitlyNamed = annotation.EndpointNames.Contains(endpointName);
var isIncludedByDefault = annotation.UseAllEndpoints && !endpoint.ExcludeReferenceEndpoint;

if (!isExplicitlyNamed && !isIncludedByDefault)
{
// Skip this endpoint since it's not in the list of endpoints we want to reference.
// Skip this endpoint since it's not explicitly named and not a default reference endpoint.
continue;
}

Expand Down Expand Up @@ -810,14 +813,25 @@ public static ReferenceExpression GetConnectionProperty(this IResourceWithConnec
}

/// <summary>
/// Injects service discovery and endpoint information as environment variables from the project resource into the destination resource, using the source resource's name as the service name.
/// Each endpoint defined on the project resource will be injected using the format defined by the <see cref="ReferenceEnvironmentInjectionAnnotation"/> on the destination resource, i.e.
/// Injects service discovery and endpoint information as environment variables from the source resource into the destination resource, using the source resource's name as the service name.
/// Each non-excluded endpoint (where <see cref="EndpointAnnotation.ExcludeReferenceEndpoint"/> is <c>false</c>) defined on the source resource will be injected using the format defined by
/// the <see cref="ReferenceEnvironmentInjectionAnnotation"/> on the destination resource, i.e.
/// either "services__{sourceResourceName}__{endpointScheme}__{endpointIndex}={uriString}" for .NET service discovery, or "{RESOURCE_ENDPOINT}={uri}" for endpoint injection.
/// </summary>
/// <typeparam name="TDestination">The destination resource.</typeparam>
/// <param name="builder">The resource where the service discovery information will be injected.</param>
/// <param name="source">The resource from which to extract service discovery information.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
/// <remarks>
/// <para>
/// All endpoints are included in the default reference set unless explicitly excluded.
/// Resource authors can opt out individual endpoints by setting <see cref="EndpointAnnotation.ExcludeReferenceEndpoint"/> to <c>true</c>
/// (for example, using <c>.WithEndpoint("endpointName", e =&gt; e.ExcludeReferenceEndpoint = true)</c>) to exclude them from this method's behavior.
/// Endpoints that have been excluded (such as management or health check endpoints) can still be referenced explicitly using
/// <see cref="WithReference{TDestination}(IResourceBuilder{TDestination}, EndpointReference)"/>
/// with <see cref="ResourceBuilderExtensions.GetEndpoint{T}(IResourceBuilder{T}, string)"/>.
/// </para>
/// </remarks>
[AspireExportIgnore(Reason = "Polyglot app hosts use the generic withReference export.")]
public static IResourceBuilder<TDestination> WithReference<TDestination>(this IResourceBuilder<TDestination> builder, IResourceBuilder<IResourceWithServiceDiscovery> source)
where TDestination : IResourceWithEnvironment
Expand All @@ -830,15 +844,26 @@ public static IResourceBuilder<TDestination> WithReference<TDestination>(this IR
}

/// <summary>
/// Injects service discovery and endpoint information as environment variables from the project resource into the destination resource, using the source resource's name as the service name.
/// Each endpoint defined on the project resource will be injected using the format defined by the <see cref="ReferenceEnvironmentInjectionAnnotation"/> on the destination resource, i.e.
/// Injects service discovery and endpoint information as environment variables from the source resource into the destination resource, using the source resource's name as the service name.
/// Each non-excluded endpoint (where <see cref="EndpointAnnotation.ExcludeReferenceEndpoint"/> is <c>false</c>) defined on the source resource will be injected using the format defined by
/// the <see cref="ReferenceEnvironmentInjectionAnnotation"/> on the destination resource, i.e.
/// either "services__{name}__{endpointScheme}__{endpointIndex}={uriString}" for .NET service discovery, or "{name}_{ENDPOINT}={uri}" for endpoint injection.
/// </summary>
/// <typeparam name="TDestination">The destination resource.</typeparam>
/// <param name="builder">The resource where the service discovery information will be injected.</param>
/// <param name="source">The resource from which to extract service discovery information.</param>
/// <param name="name">The name of the resource for the environment variable.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
/// <remarks>
/// <para>
/// All endpoints are included in the default reference set unless explicitly excluded.
/// Resource authors can opt out individual endpoints by setting <see cref="EndpointAnnotation.ExcludeReferenceEndpoint"/> to <c>true</c>
/// (for example, using <c>.WithEndpoint("endpointName", e =&gt; e.ExcludeReferenceEndpoint = true)</c>) to exclude them from this method's behavior.
/// Endpoints that have been excluded (such as management or health check endpoints) can still be referenced explicitly using
/// <see cref="WithReference{TDestination}(IResourceBuilder{TDestination}, EndpointReference)"/>
/// with <see cref="ResourceBuilderExtensions.GetEndpoint{T}(IResourceBuilder{T}, string)"/>.
/// </para>
/// </remarks>
[AspireExportIgnore(Reason = "Polyglot app hosts use the generic withReference export.")]
public static IResourceBuilder<TDestination> WithReference<TDestination>(this IResourceBuilder<TDestination> builder, IResourceBuilder<IResourceWithServiceDiscovery> source, string name)
where TDestination : IResourceWithEnvironment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6064,6 +6064,18 @@ func (s *EndpointReference) TlsEnabled() (*bool, error) {
return result.(*bool), nil
}

// ExcludeReferenceEndpoint gets the ExcludeReferenceEndpoint property
func (s *EndpointReference) ExcludeReferenceEndpoint() (*bool, error) {
reqArgs := map[string]any{
"context": SerializeValue(s.Handle()),
}
result, err := s.Client().InvokeCapability("Aspire.Hosting.ApplicationModel/EndpointReference.excludeReferenceEndpoint", reqArgs)
if err != nil {
return nil, err
}
return result.(*bool), nil
}

// Port gets the Port property
func (s *EndpointReference) Port() (*float64, error) {
reqArgs := map[string]any{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4370,6 +4370,13 @@ public boolean tlsEnabled() {
return (boolean) getClient().invokeCapability("Aspire.Hosting.ApplicationModel/EndpointReference.tlsEnabled", reqArgs);
}

/** Gets the ExcludeReferenceEndpoint property */
public boolean excludeReferenceEndpoint() {
Map<String, Object> reqArgs = new HashMap<>();
reqArgs.put("context", AspireClient.serializeValue(getHandle()));
return (boolean) getClient().invokeCapability("Aspire.Hosting.ApplicationModel/EndpointReference.excludeReferenceEndpoint", reqArgs);
}

/** Gets the Port property */
public double port() {
Map<String, Object> reqArgs = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3061,6 +3061,11 @@ def tls_enabled(self) -> bool:
args: Dict[str, Any] = { "context": serialize_value(self._handle) }
return self._client.invoke_capability("Aspire.Hosting.ApplicationModel/EndpointReference.tlsEnabled", args)

def exclude_reference_endpoint(self) -> bool:
"""Gets the ExcludeReferenceEndpoint property"""
args: Dict[str, Any] = { "context": serialize_value(self._handle) }
return self._client.invoke_capability("Aspire.Hosting.ApplicationModel/EndpointReference.excludeReferenceEndpoint", args)

def port(self) -> float:
"""Gets the Port property"""
args: Dict[str, Any] = { "context": serialize_value(self._handle) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5351,6 +5351,14 @@ impl EndpointReference {
Ok(serde_json::from_value(result)?)
}

/// Gets the ExcludeReferenceEndpoint property
pub fn exclude_reference_endpoint(&self) -> Result<bool, Box<dyn std::error::Error>> {
let mut args: HashMap<String, Value> = HashMap::new();
args.insert("context".to_string(), self.handle.to_json());
let result = self.client.invoke_capability("Aspire.Hosting.ApplicationModel/EndpointReference.excludeReferenceEndpoint", args)?;
Ok(serde_json::from_value(result)?)
}

/// Gets the Port property
pub fn port(&self) -> Result<f64, Box<dyn std::error::Error>> {
let mut args: HashMap<String, Value> = HashMap::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,16 @@ export class EndpointReference {
},
};

/** Gets the ExcludeReferenceEndpoint property */
excludeReferenceEndpoint = {
get: async (): Promise<boolean> => {
return await this._client.invokeCapability<boolean>(
'Aspire.Hosting.ApplicationModel/EndpointReference.excludeReferenceEndpoint',
{ context: this._handle }
);
},
};

/** Gets the Port property */
port = {
get: async (): Promise<number> => {
Expand Down
Loading
Loading