Let the .NET core/standard WebHostBuilder use a random port (#417)

* wip

* code reformat
This commit is contained in:
Stef Heyenrath
2020-03-14 08:51:26 +01:00
committed by GitHub
parent aeb95b02d2
commit 68ffcda53b
6 changed files with 105 additions and 51 deletions

View File

@@ -20,10 +20,10 @@ namespace WireMock.Owin
{ {
private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockMiddlewareOptions _options; private readonly IWireMockMiddlewareOptions _options;
private readonly string[] _urls;
private readonly IWireMockLogger _logger; private readonly IWireMockLogger _logger;
private Exception _runningException; private readonly HostUrlOptions _urlOptions;
private Exception _runningException;
private IWebHost _host; private IWebHost _host;
public bool IsStarted { get; private set; } public bool IsStarted { get; private set; }
@@ -34,23 +34,15 @@ namespace WireMock.Owin
public Exception RunningException => _runningException; public Exception RunningException => _runningException;
public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes) public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] HostUrlOptions urlOptions)
{ {
Check.NotNull(options, nameof(options)); Check.NotNull(options, nameof(options));
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes)); Check.NotNull(urlOptions, nameof(urlOptions));
_logger = options.Logger ?? new WireMockConsoleLogger(); _logger = options.Logger ?? new WireMockConsoleLogger();
foreach (string uriPrefix in uriPrefixes)
{
Urls.Add(uriPrefix);
PortUtils.TryExtract(uriPrefix, out string protocol, out string host, out int port);
Ports.Add(port);
}
_options = options; _options = options;
_urls = uriPrefixes; _urlOptions = urlOptions;
} }
public Task StartAsync() public Task StartAsync()
@@ -86,31 +78,35 @@ namespace WireMock.Owin
}) })
.UseKestrel(options => .UseKestrel(options =>
{ {
var urlDetails = _urlOptions.GetDetails();
#if NETSTANDARD1_3 #if NETSTANDARD1_3
if (_urls.Any(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
var urls = urlDetails.Select(u => u.Url);
if (urls.Any(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
{ {
options.UseHttps(PublicCertificateHelper.GetX509Certificate2()); options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
} }
#else #else
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x foreach (var detail in urlDetails)
foreach (string url in _urls.Where(u => u.StartsWith("http://", StringComparison.OrdinalIgnoreCase)))
{ {
PortUtils.TryExtract(url, out string protocol, out string host, out int port); if (detail.Url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
options.Listen(System.Net.IPAddress.Any, port);
}
foreach (string url in _urls.Where(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
{
PortUtils.TryExtract(url, out string protocol, out string host, out int port);
options.Listen(System.Net.IPAddress.Any, port, listenOptions =>
{ {
listenOptions.UseHttps(); // PublicCertificateHelper.GetX509Certificate2() options.Listen(System.Net.IPAddress.Any, detail.Port, listenOptions =>
}); {
listenOptions.UseHttps(); // PublicCertificateHelper.GetX509Certificate2()
});
}
else
{
options.Listen(System.Net.IPAddress.Any, detail.Port);
}
} }
#endif #endif
}) })
#if NETSTANDARD1_3 #if NETSTANDARD1_3
.UseUrls(_urls) .UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
#endif #endif
.Build(); .Build();
@@ -124,6 +120,18 @@ namespace WireMock.Owin
var appLifetime = (IApplicationLifetime)_host.Services.GetService(typeof(IApplicationLifetime)); var appLifetime = (IApplicationLifetime)_host.Services.GetService(typeof(IApplicationLifetime));
appLifetime.ApplicationStarted.Register(() => appLifetime.ApplicationStarted.Register(() =>
{ {
var addresses = _host.ServerFeatures
.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()
.Addresses;
foreach (string address in addresses)
{
Urls.Add(address.Replace("0.0.0.0", "localhost"));
PortUtils.TryExtract(address, out string protocol, out string host, out int port);
Ports.Add(port);
}
IsStarted = true; IsStarted = true;
}); });
@@ -166,5 +174,5 @@ namespace WireMock.Owin
#endif #endif
} }
} }
} }
#endif #endif

View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using WireMock.Util;
namespace WireMock.Owin
{
internal class HostUrlOptions
{
public ICollection<string> Urls { get; set; }
public bool UseSSL { get; set; }
public ICollection<(string Url, int Port)> GetDetails()
{
var list = new List<(string Url, int Port)>();
if (Urls == null)
{
int port = FindFreeTcpPort();
list.Add(($"{(UseSSL ? "https" : "http")}://localhost:{port}", port));
}
else
{
foreach (string url in Urls)
{
PortUtils.TryExtract(url, out string protocol, out string host, out int port);
list.Add((url, port));
}
}
return list;
}
private int FindFreeTcpPort()
{
#if USE_ASPNETCORE || NETSTANDARD2_0
return 0;
#else
return PortUtils.FindFreeTcpPort();
#endif
}
}
}

View File

@@ -8,7 +8,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Owin.Mappers; using WireMock.Owin.Mappers;
using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Owin namespace WireMock.Owin
@@ -18,24 +17,22 @@ namespace WireMock.Owin
private readonly IWireMockMiddlewareOptions _options; private readonly IWireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockLogger _logger; private readonly IWireMockLogger _logger;
private Exception _runningException; private Exception _runningException;
public OwinSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes) public OwinSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] HostUrlOptions urlOptions)
{ {
Check.NotNull(options, nameof(options)); Check.NotNull(options, nameof(options));
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes)); Check.NotNull(urlOptions, nameof(urlOptions));
_logger = options.Logger ?? new WireMockConsoleLogger();
foreach (string uriPrefix in uriPrefixes)
{
Urls.Add(uriPrefix);
PortUtils.TryExtract(uriPrefix, out string protocol, out string host, out int port);
Ports.Add(port);
}
_options = options; _options = options;
_logger = options.Logger ?? new WireMockConsoleLogger();
foreach (var detail in urlOptions.GetDetails())
{
Urls.Add(detail.Url);
Ports.Add(detail.Port);
}
} }
public bool IsStarted { get; private set; } public bool IsStarted { get; private set; }

View File

@@ -202,14 +202,20 @@ namespace WireMock.Server
_settings.Logger.Info("WireMock.Net by Stef Heyenrath (https://github.com/WireMock-Net/WireMock.Net)"); _settings.Logger.Info("WireMock.Net by Stef Heyenrath (https://github.com/WireMock-Net/WireMock.Net)");
_settings.Logger.Debug("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented)); _settings.Logger.Debug("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
HostUrlOptions urlOptions;
if (settings.Urls != null) if (settings.Urls != null)
{ {
Urls = settings.Urls.ToArray(); urlOptions = new HostUrlOptions
{
Urls = settings.Urls
};
} }
else else
{ {
int port = settings.Port > 0 ? settings.Port.Value : PortUtils.FindFreeTcpPort(); urlOptions = new HostUrlOptions
Urls = new[] { $"{(settings.UseSSL == true ? "https" : "http")}://localhost:{port}" }; {
UseSSL = settings.UseSSL == true
};
} }
_options.FileSystemHandler = _settings.FileSystemHandler; _options.FileSystemHandler = _settings.FileSystemHandler;
@@ -222,12 +228,10 @@ namespace WireMock.Server
_mappingConverter = new MappingConverter(_matcherMapper); _mappingConverter = new MappingConverter(_matcherMapper);
#if USE_ASPNETCORE #if USE_ASPNETCORE
_httpServer = new AspNetCoreSelfHost(_options, Urls); _httpServer = new AspNetCoreSelfHost(_options, urlOptions);
#else #else
_httpServer = new OwinSelfHost(_options, Urls); _httpServer = new OwinSelfHost(_options, urlOptions);
#endif #endif
Ports = _httpServer.Ports;
var startTask = _httpServer.StartAsync(); var startTask = _httpServer.StartAsync();
using (var ctsStartTimeout = new CancellationTokenSource(settings.StartTimeout)) using (var ctsStartTimeout = new CancellationTokenSource(settings.StartTimeout))
@@ -254,6 +258,9 @@ namespace WireMock.Server
ctsStartTimeout.Token.WaitHandle.WaitOne(ServerStartDelayInMs); ctsStartTimeout.Token.WaitHandle.WaitOne(ServerStartDelayInMs);
} }
Urls = _httpServer.Urls.ToArray();
Ports = _httpServer.Ports;
} }
if (settings.AllowBodyForAllHttpMethods == true) if (settings.AllowBodyForAllHttpMethods == true)

View File

@@ -96,7 +96,7 @@ namespace WireMock.Net.Tests
var listOfTasks = new List<Task<HttpResponseMessage>>(); var listOfTasks = new List<Task<HttpResponseMessage>>();
for (var i = 0; i < expectedCount; i++) for (var i = 0; i < expectedCount; i++)
{ {
Thread.Sleep(10); Thread.Sleep(50);
listOfTasks.Add(http.GetAsync($"{server.Urls[0]}{path}")); listOfTasks.Add(http.GetAsync($"{server.Urls[0]}{path}"));
} }
var responses = await Task.WhenAll(listOfTasks); var responses = await Task.WhenAll(listOfTasks);

View File

@@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<Authors>Stef Heyenrath</Authors> <Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;netcoreapp2.1</TargetFrameworks> <!--<TargetFrameworks>net452;netcoreapp2.1</TargetFrameworks>-->
<!--<TargetFramework>netcoreapp2.1</TargetFramework>--> <TargetFramework>netcoreapp2.1</TargetFramework>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<AssemblyName>WireMock.Net.Tests</AssemblyName> <AssemblyName>WireMock.Net.Tests</AssemblyName>
<PackageId>WireMock.Net.Tests</PackageId> <PackageId>WireMock.Net.Tests</PackageId>
@@ -58,6 +58,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'net452'"> <ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" /> <PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="3.1.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'"> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">