File: ServiceEndpointQuery.cs
Web Access
Project: src\src\Microsoft.Extensions.ServiceDiscovery.Abstractions\Microsoft.Extensions.ServiceDiscovery.Abstractions.csproj (Microsoft.Extensions.ServiceDiscovery.Abstractions)
// 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.CodeAnalysis;
 
namespace Microsoft.Extensions.ServiceDiscovery;
 
/// <summary>
/// Describes a query for endpoints of a service.
/// </summary>
public sealed class ServiceEndpointQuery
{
    private readonly string _originalString;
 
    /// <summary>
    /// Initializes a new <see cref="ServiceEndpointQuery"/> instance.
    /// </summary>
    /// <param name="originalString">The string which the query was constructed from.</param>
    /// <param name="includedSchemes">The ordered list of included URI schemes.</param>
    /// <param name="serviceName">The service name.</param>
    /// <param name="endpointName">The optional endpoint name.</param>
    private ServiceEndpointQuery(string originalString, string[] includedSchemes, string serviceName, string? endpointName)
    {
        _originalString = originalString;
        IncludedSchemes = includedSchemes;
        ServiceName = serviceName;
        EndpointName = endpointName;
    }
 
    /// <summary>
    /// Tries to parse the provided input as a service endpoint query.
    /// </summary>
    /// <param name="input">The value to parse.</param>
    /// <param name="query">The resulting query.</param>
    /// <returns><see langword="true"/> if the value was successfully parsed; otherwise <see langword="false"/>.</returns>
    public static bool TryParse(string input, [NotNullWhen(true)] out ServiceEndpointQuery? query)
    {
        bool hasScheme;
        if (!input.Contains("://", StringComparison.InvariantCulture)
            && Uri.TryCreate($"fakescheme://{input}", default, out var uri))
        {
            hasScheme = false;
        }
        else if (Uri.TryCreate(input, default, out uri))
        {
            hasScheme = true;
        }
        else
        {
            query = null;
            return false;
        }
 
        var uriHost = uri.Host;
        var segmentSeparatorIndex = uriHost.IndexOf('.');
        string host;
        string? endpointName = null;
        if (uriHost.StartsWith('_') && segmentSeparatorIndex > 1 && uriHost[^1] != '.')
        {
            endpointName = uriHost[1..segmentSeparatorIndex];
 
            // Skip the endpoint name, including its prefix ('_') and suffix ('.').
            host = uriHost[(segmentSeparatorIndex + 1)..];
        }
        else
        {
            host = uriHost;
        }
 
        // Allow multiple schemes to be separated by a '+', eg. "https+http://host:port".
        var schemes = hasScheme ? uri.Scheme.Split('+') : [];
        query = new(input, schemes, host, endpointName);
        return true;
    }
 
    /// <summary>
    /// Gets the ordered list of included URI schemes.
    /// </summary>
    public IReadOnlyList<string> IncludedSchemes { get; }
 
    /// <summary>
    /// Gets the endpoint name, or <see langword="null"/> if no endpoint name is specified.
    /// </summary>
    public string? EndpointName { get; }
 
    /// <summary>
    /// Gets the service name.
    /// </summary>
    public string ServiceName { get; }
 
    /// <inheritdoc/>
    public override string? ToString() => _originalString;
}