File: ApplicationModel\EndpointAnnotation.cs
Web Access
Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting)
// 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;
using System.Net.Sockets;
 
namespace Aspire.Hosting.ApplicationModel;
 
/// <summary>
/// Represents an endpoint annotation that describes how a service should be bound to a network.
/// </summary>
/// <remarks>
/// This class is used to specify the network protocol, port, URI scheme, transport, and other details for a service.
/// </remarks>
[DebuggerDisplay("Type = {GetType().Name,nq}, Name = {Name}")]
public sealed class EndpointAnnotation : IResourceAnnotation
{
    private string? _transport;
    private int? _port;
    private bool _portSetToNull;
    private int? _targetPort;
    private bool _targetPortSetToNull;
    /// <summary>
    /// Initializes a new instance of <see cref="EndpointAnnotation"/>.
    /// </summary>
    /// <param name="protocol">Network protocol: TCP or UDP are supported today, others possibly in future.</param>
    /// <param name="uriScheme">If a service is URI-addressable, this is the URI scheme to use for constructing service URI.</param>
    /// <param name="transport">Transport that is being used (e.g. http, http2, http3 etc).</param>
    /// <param name="name">Name of the service.</param>
    /// <param name="port">Desired port for the service.</param>
    /// <param name="targetPort">This is the port the resource is listening on. If the endpoint is used for the container, it is the container port.</param>
    /// <param name="isExternal">Indicates that this endpoint should be exposed externally at publish time.</param>
    /// <param name="isProxied">Specifies if the endpoint will be proxied by DCP. Defaults to true.</param>
    public EndpointAnnotation(ProtocolType protocol, string? uriScheme = null, string? transport = null, string? name = null, int? port = null, int? targetPort = null, bool? isExternal = null, bool isProxied = true)
    {
        // If the URI scheme is null, we'll adopt either udp:// or tcp:// based on the
        // protocol. If the name is null, we'll use the URI scheme as the default. This
        // is because we eventually always need these values to be populated so lets do
        // it up front.
 
        uriScheme ??= protocol.ToString().ToLowerInvariant();
        name ??= uriScheme;
 
        ModelName.ValidateName(nameof(EndpointAnnotation), name);
 
        Protocol = protocol;
        UriScheme = uriScheme;
        _transport = transport;
        Name = name;
        _port = port;
        _targetPort = targetPort;
        IsExternal = isExternal ?? false;
        IsProxied = isProxied;
    }
 
    /// <summary>
    ///  Name of the service
    /// </summary>
    public string Name { get; set; }
 
    /// <summary>
    /// Network protocol: TCP or UDP are supported today, others possibly in future.
    /// </summary>
    public ProtocolType Protocol { get; set; }
 
    /// <summary>
    /// Desired port for the service
    /// </summary>
    public int? Port
    {
        // For proxy-less Endpoints the client port and target port should be the same.
        // Note that this is just a "sensible default"--the consumer of the EndpointAnnotation is free
        // to change Port and TargetPort after the annotation is created, but if the final values are inconsistent,
        // the associated resource may fail to run.
        // It also depends on what the EndpointAnnotation is applied to.
        // In the Container case the TargetPort is the port that the process listens on inside the container,
        //  and the Port is the host interface port, so it is fine for them to be different.
        get => _port ?? (IsProxied || _portSetToNull ? null : _targetPort);
        set
        {
            _port = value;
            _portSetToNull = value == null;
        }
    }
 
    /// <summary>
    /// This is the port the resource is listening on. If the endpoint is used for the container, it is the container port.
    /// </summary>
    /// <remarks>
    /// Defaults to <see cref="Port"/>.
    /// </remarks>
    public int? TargetPort
    {
        // See comment on the Port setter, as this is the reciprocal logic
        get => _targetPort ?? (IsProxied || _targetPortSetToNull ? null : _port);
        set
        {
            _targetPort = value;
            _targetPortSetToNull = value == null;
        }
    }
 
    /// <summary>
    /// If a service is URI-addressable, this property will contain the URI scheme to use for constructing service URI.
    /// </summary>
    public string UriScheme { get; set; }
 
    /// <summary>
    /// This is the address the resource is listening on. By default it is localhost.
    /// </summary>
    public string TargetHost { get; set; } = "localhost";
 
    /// <summary>
    /// Transport that is being used (e.g. http, http2, http3 etc).
    /// </summary>
    public string Transport
    {
        get => _transport ?? (UriScheme == "http" || UriScheme == "https" ? "http" : Protocol.ToString().ToLowerInvariant());
        set => _transport = value;
    }
 
    /// <summary>
    /// Indicates that this endpoint should be exposed externally at publish time.
    /// </summary>
    public bool IsExternal { get; set; }
 
    /// <summary>
    /// Indicates that this endpoint should be managed by DCP. This means it can be replicated and use a different port internally than the one publicly exposed.
    /// Setting to false means the endpoint will be handled and exposed by the resource.
    /// </summary>
    /// <remarks>Defaults to <c>true</c>.</remarks>
    public bool IsProxied { get; set; } = true;
 
    /// <summary>
    /// Gets or sets a value indicating whether the endpoint is from a launch profile.
    /// </summary>
    internal bool FromLaunchProfile { get; set; }
 
    /// <summary>
    /// The environment variable that contains the target port. Setting prevents a variable from flowing into ASPNETCORE_URLS for project resources.
    /// </summary>
    internal string? TargetPortEnvironmentVariable { get; set; }
 
    /// <summary>
    /// Gets or sets the allocated endpoint.
    /// </summary>
    public AllocatedEndpoint? AllocatedEndpoint { get; set; }
}