我使用 OWIN 来自托管 Web API,同时使用 NCrunch并行运行我的测试,我在 BeforeEach 中启动它并在 AfterEach 方法中停止。
在每次测试之前,我都试图获得可用的空闲端口,但通常 85 个测试中有 5-10 个测试失败,但有以下例外:
System.Net.HttpListenerException : Failed to listen on prefix
'http://localhost:3369/' because it conflicts with an existing registration on the machine.
所以看起来,有时我没有得到可用的端口。我尝试使用Interlocked类在多个线程之间共享最后使用的端口,但它没有帮助。
这是我的测试基类:
public class BaseSteps
{
private const int PortRangeStart = 3368;
private const int PortRangeEnd = 8968;
private static long _portNumber = PortRangeStart;
private IDisposable _webServer;
//.....
[BeforeScenario]
public void Before()
{
Url = GetFullUrl();
_webServer = WebApp.Start<TestStartup>(Url);
}
[AfterScenario]
public void After()
{
_webServer.Dispose();
}
private static string GetFullUrl()
{
var ipAddress = IPAddress.Loopback;
var portAvailable = GetAvailablePort(PortRangeStart, PortRangeEnd, ipAddress);
return String.Format("http://{0}:{1}/", "localhost", portAvailable);
}
private static int GetAvailablePort(int rangeStart, int rangeEnd, IPAddress ip, bool includeIdlePorts = false)
{
IPGlobalProperties ipProps = IPGlobalProperties.GetIPGlobalProperties();
// if the ip we want a port on is an 'any' or loopback port we need to exclude all ports that are active on any IP
Func<IPAddress, bool> isIpAnyOrLoopBack = i => IPAddress.Any.Equals(i) ||
IPAddress.IPv6Any.Equals(i) ||
IPAddress.Loopback.Equals(i) ||
IPAddress.IPv6Loopback.
Equals(i);
// get all active ports on specified IP.
List<ushort> excludedPorts = new List<ushort>();
// if a port is open on an 'any' or 'loopback' interface then include it in the excludedPorts
excludedPorts.AddRange(from n in ipProps.GetActiveTcpConnections()
where
n.LocalEndPoint.Port >= rangeStart &&
n.LocalEndPoint.Port <= rangeEnd && (
isIpAnyOrLoopBack(ip) || n.LocalEndPoint.Address.Equals(ip) ||
isIpAnyOrLoopBack(n.LocalEndPoint.Address)) &&
(!includeIdlePorts || n.State != TcpState.TimeWait)
select (ushort)n.LocalEndPoint.Port);
excludedPorts.AddRange(from n in ipProps.GetActiveTcpListeners()
where n.Port >= rangeStart && n.Port <= rangeEnd && (
isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
select (ushort)n.Port);
excludedPorts.AddRange(from n in ipProps.GetActiveUdpListeners()
where n.Port >= rangeStart && n.Port <= rangeEnd && (
isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
select (ushort)n.Port);
excludedPorts.Sort();
for (int port = rangeStart; port <= rangeEnd; port++)
{
if (!excludedPorts.Contains((ushort)port) && Interlocked.Read(ref _portNumber) < port)
{
Interlocked.Increment(ref _portNumber);
return port;
}
}
return 0;
}
}
有谁知道如何确保我总是得到可用的端口?