mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-27 03:41:50 +01:00
Respect start timeout setting and expose exception from server startup (#117)
* Respect start timeout setting and expose exception from server startup * Dispose running servers properly on error happening * Addressed comments from Stef
This commit is contained in:
committed by
Stef Heyenrath
parent
ac72973cc4
commit
2d2a2dd6fc
@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Builder;
|
|||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
using WireMock.HttpsCertificate;
|
using WireMock.HttpsCertificate;
|
||||||
|
using WireMock.Logging;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
@@ -18,6 +19,8 @@ namespace WireMock.Owin
|
|||||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||||
private readonly WireMockMiddlewareOptions _options;
|
private readonly WireMockMiddlewareOptions _options;
|
||||||
private readonly string[] _urls;
|
private readonly string[] _urls;
|
||||||
|
private readonly IWireMockLogger _logger;
|
||||||
|
private Exception _runningException;
|
||||||
|
|
||||||
private IWebHost _host;
|
private IWebHost _host;
|
||||||
|
|
||||||
@@ -27,11 +30,15 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
public List<int> Ports { get; } = new List<int>();
|
public List<int> Ports { get; } = new List<int>();
|
||||||
|
|
||||||
|
public Exception RunningException => _runningException;
|
||||||
|
|
||||||
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||||
{
|
{
|
||||||
Check.NotNull(options, nameof(options));
|
Check.NotNull(options, nameof(options));
|
||||||
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
||||||
|
|
||||||
|
_logger = options.Logger ?? new WireMockConsoleLogger();
|
||||||
|
|
||||||
foreach (string uriPrefix in uriPrefixes)
|
foreach (string uriPrefix in uriPrefixes)
|
||||||
{
|
{
|
||||||
Urls.Add(uriPrefix);
|
Urls.Add(uriPrefix);
|
||||||
@@ -89,20 +96,35 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
IsStarted = true;
|
IsStarted = true;
|
||||||
|
|
||||||
#if NETSTANDARD1_3
|
|
||||||
Console.WriteLine("WireMock.Net server using netstandard1.3");
|
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
_host.Run(_cts.Token);
|
StartServers();
|
||||||
}, _cts.Token);
|
}, _cts.Token);
|
||||||
#else
|
}
|
||||||
System.Console.WriteLine("WireMock.Net server using netstandard2.0");
|
|
||||||
|
|
||||||
return Task.Run(() =>
|
private void StartServers()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
IsStarted = true;
|
||||||
|
#if NETSTANDARD1_3
|
||||||
|
_logger.Info("WireMock.Net server using netstandard1.3");
|
||||||
|
_host.Run(_cts.Token);
|
||||||
|
#else
|
||||||
|
_logger.Info("WireMock.Net server using netstandard2.0");
|
||||||
_host.Run();
|
_host.Run();
|
||||||
}, _cts.Token);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_runningException = e;
|
||||||
|
_logger.Error(e.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsStarted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync()
|
public Task StopAsync()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
{
|
{
|
||||||
@@ -29,6 +30,11 @@ namespace WireMock.Owin
|
|||||||
/// </value>
|
/// </value>
|
||||||
List<int> Ports { get; }
|
List<int> Ports { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The exception occurred when the host is running
|
||||||
|
/// </summary>
|
||||||
|
Exception RunningException { get; }
|
||||||
|
|
||||||
Task StartAsync();
|
Task StartAsync();
|
||||||
|
|
||||||
Task StopAsync();
|
Task StopAsync();
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#if !NETSTANDARD
|
#if !NETSTANDARD
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.Owin.Hosting;
|
||||||
|
using Owin;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using WireMock.Validation;
|
|
||||||
using Owin;
|
|
||||||
using Microsoft.Owin.Hosting;
|
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
|
using WireMock.Logging;
|
||||||
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
{
|
{
|
||||||
@@ -15,12 +16,16 @@ namespace WireMock.Owin
|
|||||||
{
|
{
|
||||||
private readonly WireMockMiddlewareOptions _options;
|
private readonly WireMockMiddlewareOptions _options;
|
||||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||||
|
private readonly IWireMockLogger _logger;
|
||||||
|
private Exception _runningException;
|
||||||
|
|
||||||
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
|
||||||
{
|
{
|
||||||
Check.NotNull(options, nameof(options));
|
Check.NotNull(options, nameof(options));
|
||||||
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
|
||||||
|
|
||||||
|
_logger = options.Logger ?? new WireMockConsoleLogger();
|
||||||
|
|
||||||
foreach (string uriPrefix in uriPrefixes)
|
foreach (string uriPrefix in uriPrefixes)
|
||||||
{
|
{
|
||||||
Urls.Add(uriPrefix);
|
Urls.Add(uriPrefix);
|
||||||
@@ -38,6 +43,8 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
public List<int> Ports { get; } = new List<int>();
|
public List<int> Ports { get; } = new List<int>();
|
||||||
|
|
||||||
|
public Exception RunningException => _runningException;
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public Task StartAsync()
|
public Task StartAsync()
|
||||||
{
|
{
|
||||||
@@ -58,37 +65,46 @@ namespace WireMock.Owin
|
|||||||
private void StartServers()
|
private void StartServers()
|
||||||
{
|
{
|
||||||
#if NET46
|
#if NET46
|
||||||
Console.WriteLine("WireMock.Net server using .net 4.6.x or higher");
|
_logger.Info("WireMock.Net server using .net 4.6.x or higher");
|
||||||
#else
|
#else
|
||||||
Console.WriteLine("WireMock.Net server using .net 4.5.x or higher");
|
_logger.Info("WireMock.Net server using .net 4.5.x or higher");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Action<IAppBuilder> startup = app =>
|
|
||||||
{
|
|
||||||
app.Use<GlobalExceptionMiddleware>(_options);
|
|
||||||
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
|
||||||
app.Use<WireMockMiddleware>(_options);
|
|
||||||
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
|
||||||
};
|
|
||||||
|
|
||||||
var servers = new List<IDisposable>();
|
var servers = new List<IDisposable>();
|
||||||
foreach (var url in Urls)
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
servers.Add(WebApp.Start(url, startup));
|
Action<IAppBuilder> startup = app =>
|
||||||
|
{
|
||||||
|
app.Use<GlobalExceptionMiddleware>(_options);
|
||||||
|
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
||||||
|
app.Use<WireMockMiddleware>(_options);
|
||||||
|
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var url in Urls)
|
||||||
|
{
|
||||||
|
servers.Add(WebApp.Start(url, startup));
|
||||||
|
}
|
||||||
|
|
||||||
|
IsStarted = true;
|
||||||
|
|
||||||
|
// WaitHandle is signaled when the token is cancelled,
|
||||||
|
// which will be more efficent than Thread.Sleep in while loop
|
||||||
|
_cts.Token.WaitHandle.WaitOne();
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
IsStarted = true;
|
|
||||||
|
|
||||||
while (!_cts.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
Thread.Sleep(30000);
|
// Expose exception of starting host, otherwise it's hard to be troubleshooting if keeping quiet
|
||||||
|
// For example, WebApp.Start will fail with System.MissingMemberException if Microsoft.Owin.Host.HttpListener.dll is being located
|
||||||
|
// https://stackoverflow.com/questions/25090211/owin-httplistener-not-located/31369857
|
||||||
|
_runningException = e;
|
||||||
|
_logger.Error(e.ToString());
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
IsStarted = false;
|
|
||||||
|
|
||||||
foreach (var server in servers)
|
|
||||||
{
|
{
|
||||||
server.Dispose();
|
IsStarted = false;
|
||||||
|
// Dispose all servers in finally block to make sure clean up allocated resource on error happening
|
||||||
|
servers.ForEach((s) => s.Dispose());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.Owin;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
|
using WireMock.ResponseProviders;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
using WireMock.Owin;
|
|
||||||
using WireMock.ResponseProviders;
|
|
||||||
|
|
||||||
namespace WireMock.Server
|
namespace WireMock.Server
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ namespace WireMock.Server
|
|||||||
/// Gets a value indicating whether this server is started.
|
/// Gets a value indicating whether this server is started.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool IsStarted { get; }
|
public bool IsStarted { get => _httpServer == null ? false : _httpServer.IsStarted; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the ports.
|
/// Gets the ports.
|
||||||
@@ -186,10 +186,23 @@ namespace WireMock.Server
|
|||||||
|
|
||||||
_httpServer.StartAsync();
|
_httpServer.StartAsync();
|
||||||
|
|
||||||
// Fix for 'Bug: Server not listening after Start() returns (on macOS)'
|
using (var ctsStartTimeout = new CancellationTokenSource(settings.StartTimeout))
|
||||||
Task.Delay(ServerStartDelay).Wait();
|
{
|
||||||
|
while (!_httpServer.IsStarted)
|
||||||
IsStarted = _httpServer.IsStarted;
|
{
|
||||||
|
// Throw out exception if service start fails
|
||||||
|
if (_httpServer.RunningException != null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Service start failed with error: {_httpServer.RunningException.Message}", _httpServer.RunningException);
|
||||||
|
}
|
||||||
|
// Respect start timeout setting by throwing TimeoutException
|
||||||
|
if (ctsStartTimeout.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new TimeoutException($"Service start timed out after {TimeSpan.FromMilliseconds(settings.StartTimeout)}");
|
||||||
|
}
|
||||||
|
ctsStartTimeout.Token.WaitHandle.WaitOne(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.AllowPartialMapping == true)
|
if (settings.AllowPartialMapping == true)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user