| File: Helpers\Network.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Tests\Aspire.Hosting.Tests.csproj (Aspire.Hosting.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net; using System.Net.Sockets; using Polly; using Polly.Retry; using Polly.Timeout; namespace Aspire.Hosting.Tests.Helpers; internal static class Network { /// <summary> /// Finds an available (unoccupied) TCP port on the specified network address by attempting /// to bind a socket to randomly chosen ports within the given range. /// </summary> /// <param name="minPort">The inclusive lower bound of the random port range.</param> /// <param name="maxPort">The inclusive upper bound of the random port range.</param> /// <param name="address">The network address to bind to (e.g. "127.0.0.1").</param> /// <returns>An available port number.</returns> /// <exception cref="InvalidOperationException">Thrown when no available port is found within the timeout period.</exception> public static async Task<int> GetAvailablePortAsync( int minPort = 10000, int maxPort = 20000, string address = "127.0.0.1") { var triedPorts = new List<int>(); var random = new Random(); var ipAddress = IPAddress.Parse(address); var pipeline = new ResiliencePipelineBuilder<int>() .AddTimeout(new TimeoutStrategyOptions { Timeout = TimeSpan.FromSeconds(10) }) .AddRetry(new RetryStrategyOptions<int> { ShouldHandle = new PredicateBuilder<int>().Handle<SocketException>(), BackoffType = DelayBackoffType.Exponential, Delay = TimeSpan.FromMilliseconds(50), MaxDelay = TimeSpan.FromSeconds(2), MaxRetryAttempts = int.MaxValue, }) .Build(); try { return await pipeline.ExecuteAsync(async (ct) => { var port = random.Next(minPort, maxPort + 1); triedPorts.Add(port); using var socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); socket.Bind(new IPEndPoint(ipAddress, port)); socket.Close(); return port; }); } catch (TimeoutRejectedException) { throw new InvalidOperationException( $"Could not find an available port on address '{address}' after 10 seconds. " + $"Tried ports: {string.Join(", ", triedPorts)}"); } } }