File: NativeServerOptions.cs
Web Access
Project: src\src\Aspire.Hosting.Native.Server\Aspire.Hosting.Native.Server.csproj (Aspire.Hosting.Native.Server)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Text.Json;
using System.Text.Json.Serialization;
using Aspire.Hosting.Native.Runtime;
 
namespace Aspire.Hosting.Native.Server;
 
/// <summary>Defines validated server policies with named defaults, not scenario-dependent settings.</summary>
internal sealed class NativeServerOptions
{
    public const int DefaultMaximumRequestBytes = 256 * 1024;
    [JsonIgnore]
    public TimeProvider TimeProvider { get; init; } = TimeProvider.System;
    public NativeRuntimeOptions Runtime { get; set; } = new();
    public TimeSpan ControllerStartupTimeout { get; set; } = TimeSpan.FromSeconds(45);
    public TimeSpan ControllerRequestTimeout { get; set; } = TimeSpan.FromSeconds(20);
    public TimeSpan ControllerLogReadTimeout { get; set; } = TimeSpan.FromSeconds(10);
    public TimeSpan CleanupTimeout { get; set; } = TimeSpan.FromSeconds(45);
    public TimeSpan AuthenticationTimeout { get; set; } = TimeSpan.FromSeconds(10);
    public TimeSpan BackchannelFirstRequestTimeout { get; set; } = TimeSpan.FromSeconds(10);
    public TimeSpan ProviderInvocationTimeout { get; set; } = TimeSpan.FromSeconds(30);
    public TimeSpan ProviderRegistrationTimeout { get; set; } = TimeSpan.FromSeconds(30);
    public TimeSpan RetryInterval { get; set; } = TimeSpan.FromMilliseconds(100);
    public TimeSpan DashboardShutdownTimeout { get; set; } = TimeSpan.FromSeconds(10);
    public int MaximumConcurrentRequests { get; set; } = 64;
    public int MaximumConnections { get; set; } = 32;
    public int MaximumRequestBytes { get; set; } = DefaultMaximumRequestBytes;
    public int MaximumHandlesPerConnection { get; set; } = 4096;
    public int MaximumCliStreams { get; set; } = 64;
    public int RetainedAppHostLogEntries { get; set; } = 256;
 
    public static NativeServerOptions Load(string? path)
    {
        NativeServerOptions options;
        if (path is null)
        {
            options = new();
        }
        else
        {
            using var stream = File.OpenRead(path);
            options = JsonSerializer.Deserialize(stream, NativeServerJsonContext.Default.NativeServerOptions)
                ?? throw new InvalidDataException("Server options cannot be null.");
        }
        options.Validate();
 
        return options;
    }
 
    public void Validate()
    {
        ArgumentNullException.ThrowIfNull(Runtime);
        ArgumentNullException.ThrowIfNull(TimeProvider);
        Runtime.TimeProvider = TimeProvider;
        Runtime.Validate();
        foreach (var duration in new[] { ControllerStartupTimeout, ControllerRequestTimeout, ControllerLogReadTimeout, CleanupTimeout,
            AuthenticationTimeout, BackchannelFirstRequestTimeout, ProviderInvocationTimeout, ProviderRegistrationTimeout,
            RetryInterval, DashboardShutdownTimeout })
        {
            if (duration <= TimeSpan.Zero || duration.TotalMilliseconds > int.MaxValue)
            {
                throw new ArgumentException("Server lifecycle intervals must be positive bounded durations.");
            }
        }
        if (RetryInterval > ControllerStartupTimeout || MaximumConcurrentRequests is < 1 or > 4096 ||
            MaximumCliStreams is < 1 or > 4096 || RetainedAppHostLogEntries is < 1 or > 65536 ||
            MaximumConnections is < 1 or > 4096 || MaximumRequestBytes is < 1024 or > 16 * 1024 * 1024 ||
            MaximumHandlesPerConnection is < 1 or > 65536)
        {
            throw new ArgumentException("Invalid native server capacity or retry interval.");
        }
    }
}
 
[JsonSerializable(typeof(NativeServerOptions))]
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, RespectNullableAnnotations = true)]
internal sealed partial class NativeServerJsonContext : JsonSerializerContext;