Version 2.x

This commit is contained in:
Stef Heyenrath
2025-08-30 10:24:07 +02:00
parent 358590918e
commit 034766a2d6
83 changed files with 1077 additions and 999 deletions

View File

@@ -1,6 +1,6 @@
// Copyright © WireMock.Net
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
#if NET8_0
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;

View File

@@ -1,12 +1,11 @@
// Copyright © WireMock.Net
#if USE_ASPNETCORE && !NETSTANDARD1_3
//#if USE_ASPNETCORE && !NETSTANDARD1_3
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using CertificateLoader = WireMock.HttpsCertificate.CertificateLoader;
@@ -38,7 +37,7 @@ internal partial class AspNetCoreSelfHost
options.ServerCertificate = CertificateLoader.LoadCertificate(wireMockMiddlewareOptions, urlDetail.Host);
}
options.ClientCertificateMode = (ClientCertificateMode)wireMockMiddlewareOptions.ClientCertificateMode;
options.ClientCertificateMode = wireMockMiddlewareOptions.ClientCertificateMode;
if (wireMockMiddlewareOptions.AcceptAnyClientCertificate)
{
options.ClientCertificateValidation = (_, _, _) => true;
@@ -47,7 +46,7 @@ internal partial class AspNetCoreSelfHost
if (urlDetail.IsHttp2)
{
listenOptions.Protocols = HttpProtocols.Http2;
SetHttp2AsProtocolsOnListenOptions(listenOptions);
}
});
continue;
@@ -55,10 +54,7 @@ internal partial class AspNetCoreSelfHost
if (urlDetail.IsHttp2)
{
Listen(kestrelOptions, urlDetail, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
Listen(kestrelOptions, urlDetail, SetHttp2AsProtocolsOnListenOptions);
continue;
}
@@ -66,6 +62,15 @@ internal partial class AspNetCoreSelfHost
}
}
private static void SetHttp2AsProtocolsOnListenOptions(ListenOptions listenOptions)
{
#if NET8_0_OR_GREATER
listenOptions.Protocols = HttpProtocols.Http2;
#else
throw new NotSupportedException("HTTP/2 is only supported in .NET 8 or greater.");
#endif
}
private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action<ListenOptions> configure)
{
// Listens on any IP with the given port.
@@ -112,4 +117,4 @@ internal static class IWebHostBuilderExtensions
});
}
}
#endif
//#endif

View File

@@ -1,57 +1,57 @@
// Copyright © WireMock.Net
#if USE_ASPNETCORE && NETSTANDARD1_3
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate;
//#if USE_ASPNETCORE && NETSTANDARD1_3
//using System.Collections.Generic;
//using Microsoft.AspNetCore.Hosting;
//using Microsoft.AspNetCore.Server.Kestrel;
//using Microsoft.AspNetCore.Server.Kestrel.Https;
//using Microsoft.Extensions.Configuration;
//using Microsoft.Extensions.DependencyInjection;
//using WireMock.HttpsCertificate;
namespace WireMock.Owin;
//namespace WireMock.Owin;
internal partial class AspNetCoreSelfHost
{
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
{
options.Limits.MaxRequestBufferSize = null;
options.Limits.MaxRequestHeaderCount = 100;
options.Limits.MaxResponseBufferSize = null;
}
//internal partial class AspNetCoreSelfHost
//{
// private static void SetKestrelOptionsLimits(KestrelServerOptions options)
// {
// options.Limits.MaxRequestBufferSize = null;
// options.Limits.MaxRequestHeaderCount = 100;
// options.Limits.MaxResponseBufferSize = null;
// }
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
{
foreach (var urlDetail in urlDetails)
{
if (urlDetail.IsHttps)
{
options.UseHttps(new HttpsConnectionFilterOptions
{
ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined ? CertificateLoader.LoadCertificate(wireMockMiddlewareOptions, urlDetail.Host) : PublicCertificateHelper.GetX509Certificate2(),
ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate ? (_, _, _) => true : null
});
}
}
}
}
// private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
// {
// foreach (var urlDetail in urlDetails)
// {
// if (urlDetail.IsHttps)
// {
// options.UseHttps(new HttpsConnectionFilterOptions
// {
// ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined ? CertificateLoader.LoadCertificate(wireMockMiddlewareOptions, urlDetail.Host) : PublicCertificateHelper.GetX509Certificate2(),
// ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
// ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate ? (_, _, _) => true : null
// });
// }
// }
// }
//}
internal static class IWebHostBuilderExtensions
{
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
//internal static class IWebHostBuilderExtensions
//{
// internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
{
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
// internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
// {
// var configuration = new ConfigurationBuilder()
// .AddEnvironmentVariables()
// .Build();
return builder.ConfigureServices(services =>
{
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
});
}
}
// return builder.ConfigureServices(services =>
// {
// services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
// });
// }
//}
#endif
//#endif

View File

@@ -1,10 +1,9 @@
// Copyright © WireMock.Net
#if USE_ASPNETCORE
//#if USE_ASPNETCORE
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
@@ -74,7 +73,7 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
services.AddSingleton<IGuidUtils, GuidUtils>();
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
#if NET8_0_OR_GREATER
AddCors(services);
#endif
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
@@ -83,7 +82,7 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
{
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
#if NET8_0_OR_GREATER
UseCors(appBuilder);
#endif
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
@@ -100,9 +99,9 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
})
.ConfigureKestrelServerOptions()
#if NETSTANDARD1_3
.UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
#endif
//#if NETSTANDARD1_3
// .UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
//#endif
.Build();
return RunHost(_cts.Token);
@@ -112,7 +111,7 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
{
try
{
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
#if NET8_0_OR_GREATER
var appLifetime = _host.Services.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
#else
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
@@ -134,23 +133,9 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
IsStarted = true;
});
#if NETSTANDARD1_3
_logger.Info("Server using netstandard1.3");
#elif NETSTANDARD2_0
_logger.Info("Server using netstandard2.0");
#elif NETSTANDARD2_1
_logger.Info("Server using netstandard2.1");
#elif NETCOREAPP3_1
_logger.Info("Server using .NET Core App 3.1");
#elif NET5_0
_logger.Info("Server using .NET 5.0");
#elif NET6_0
_logger.Info("Server using .NET 6.0");
#elif NET7_0
_logger.Info("Server using .NET 7.0");
#elif NET8_0
#if NET8_0
_logger.Info("Server using .NET 8.0");
#elif NET46
#elif NET48
_logger.Info("Server using .NET Framework 4.6.1 or higher");
#endif
@@ -179,11 +164,11 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
_cts.Cancel();
IsStarted = false;
#if NETSTANDARD1_3
return Task.CompletedTask;
#else
//#if NETSTANDARD1_3
// return Task.CompletedTask;
//#else
return _host.StopAsync();
#endif
//#endif
}
}
#endif
//#endif

View File

@@ -3,68 +3,69 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
#if !USE_ASPNETCORE
using Microsoft.Owin;
using IContext = Microsoft.Owin.IOwinContext;
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
using Next = Microsoft.Owin.OwinMiddleware;
#else
using OwinMiddleware = System.Object;
using IContext = Microsoft.AspNetCore.Http.HttpContext;
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
#endif
using WireMock.Owin.Mappers;
using Stef.Validation;
using Microsoft.AspNetCore.Http;
//#if !USE_ASPNETCORE
//using Microsoft.Owin;
//using IContext = Microsoft.Owin.IOwinContext;
//using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
//using Next = Microsoft.Owin.OwinMiddleware;
//#else
//using OwinMiddleware = System.Object;
//using IContext = Microsoft.AspNetCore.Http.HttpContext;
//using Next = Microsoft.AspNetCore.Http.RequestDelegate;
//#endif
namespace WireMock.Owin
namespace WireMock.Owin;
internal class GlobalExceptionMiddleware //: OwinMiddleware
{
internal class GlobalExceptionMiddleware : OwinMiddleware
private readonly IWireMockMiddlewareOptions _options;
private readonly IOwinResponseMapper _responseMapper;
//#if !USE_ASPNETCORE
// public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper) : base(next)
// {
// _options = Guard.NotNull(options);
// _responseMapper = Guard.NotNull(responseMapper);;
// }
//#else
public GlobalExceptionMiddleware(RequestDelegate next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper)
{
private readonly IWireMockMiddlewareOptions _options;
private readonly IOwinResponseMapper _responseMapper;
Next = next;
_options = Guard.NotNull(options);
_responseMapper = Guard.NotNull(responseMapper);
}
//#endif
#if !USE_ASPNETCORE
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper) : base(next)
{
_options = Guard.NotNull(options);
_responseMapper = Guard.NotNull(responseMapper);;
}
#else
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper)
{
Next = next;
_options = Guard.NotNull(options);
_responseMapper = Guard.NotNull(responseMapper);
}
#endif
//#if USE_ASPNETCORE
public RequestDelegate? Next { get; }
//#endif
#if USE_ASPNETCORE
public Next Next { get; }
#endif
//#if !USE_ASPNETCORE
// public override Task Invoke(IContext ctx)
//#else
public Task Invoke(HttpContext ctx)
//#endif
{
return InvokeInternalAsync(ctx);
}
#if !USE_ASPNETCORE
public override Task Invoke(IContext ctx)
#else
public Task Invoke(IContext ctx)
#endif
private async Task InvokeInternalAsync(HttpContext ctx)
{
try
{
return InvokeInternalAsync(ctx);
}
private async Task InvokeInternalAsync(IContext ctx)
{
try
if (Next != null)
{
if (Next != null)
{
await Next.Invoke(ctx).ConfigureAwait(false);
}
}
catch (Exception ex)
{
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false);
await Next.Invoke(ctx).ConfigureAwait(false);
}
}
catch (Exception ex)
{
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false);
}
}
}
}

View File

@@ -2,21 +2,22 @@
using System;
using System.Collections.Concurrent;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types;
using WireMock.Util;
using System.Security.Cryptography.X509Certificates;
using ClientCertificateMode = Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode;
using JetBrains.Annotations;
#if !USE_ASPNETCORE
using Owin;
#else
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
using Microsoft.Extensions.DependencyInjection;
#endif
//#if !USE_ASPNETCORE
//using Owin;
//#else
//using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
//using Microsoft.Extensions.DependencyInjection;
//#endif
namespace WireMock.Owin;
@@ -40,11 +41,11 @@ internal interface IWireMockMiddlewareOptions
int? MaxRequestLogCount { get; set; }
Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
Action<IApplicationBuilder>? PreWireMockMiddlewareInit { get; set; }
Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
Action<IApplicationBuilder>? PostWireMockMiddlewareInit { get; set; }
#if USE_ASPNETCORE
//#if USE_ASPNETCORE
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
CorsPolicyOptions? CorsPolicyOptions { get; set; }
@@ -52,7 +53,7 @@ internal interface IWireMockMiddlewareOptions
ClientCertificateMode ClientCertificateMode { get; set; }
bool AcceptAnyClientCertificate { get; set; }
#endif
//#endif
IFileSystemHandler? FileSystemHandler { get; set; }

View File

@@ -1,25 +1,25 @@
// Copyright © WireMock.Net
using System.Threading.Tasks;
#if !USE_ASPNETCORE
using IRequest = Microsoft.Owin.IOwinRequest;
#else
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
#endif
using Microsoft.AspNetCore.Http;
//#if !USE_ASPNETCORE
//using IRequest = Microsoft.Owin.IOwinRequest;
//#else
//using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
//#endif
namespace WireMock.Owin.Mappers
namespace WireMock.Owin.Mappers;
/// <summary>
/// IOwinRequestMapper
/// </summary>
internal interface IOwinRequestMapper
{
/// <summary>
/// IOwinRequestMapper
/// MapAsync IRequest to RequestMessage
/// </summary>
internal interface IOwinRequestMapper
{
/// <summary>
/// MapAsync IRequest to RequestMessage
/// </summary>
/// <param name="request">The OwinRequest/HttpRequest</param>
/// <param name="options">The WireMockMiddlewareOptions</param>
/// <returns>RequestMessage</returns>
Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options);
}
/// <param name="request">The HttpRequest</param>
/// <param name="options">The WireMockMiddlewareOptions</param>
/// <returns>RequestMessage</returns>
Task<RequestMessage> MapAsync(HttpRequest request, IWireMockMiddlewareOptions options);
}

View File

@@ -1,11 +1,13 @@
// Copyright © WireMock.Net
using System.Threading.Tasks;
#if !USE_ASPNETCORE
using IResponse = Microsoft.Owin.IOwinResponse;
#else
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
#endif
using Microsoft.AspNetCore.Http;
//#if !USE_ASPNETCORE
//using IResponse = Microsoft.Owin.IOwinResponse;
//#else
//using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
//#endif
namespace WireMock.Owin.Mappers;
@@ -18,6 +20,6 @@ internal interface IOwinResponseMapper
/// Map ResponseMessage to IResponse.
/// </summary>
/// <param name="responseMessage">The ResponseMessage</param>
/// <param name="response">The OwinResponse/HttpResponse</param>
Task MapAsync(IResponseMessage? responseMessage, IResponse response);
}
/// <param name="response">The HttpResponse</param>
Task MapAsync(IResponseMessage? responseMessage, HttpResponse response);
}

View File

@@ -4,15 +4,17 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using WireMock.Http;
using WireMock.Models;
using WireMock.Util;
#if !USE_ASPNETCORE
using IRequest = Microsoft.Owin.IOwinRequest;
#else
using Microsoft.AspNetCore.Http.Extensions;
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
#endif
//#if !USE_ASPNETCORE
//using IRequest = Microsoft.Owin.IOwinRequest;
//#else
//using Microsoft.AspNetCore.Http.Extensions;
//using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
//#endif
namespace WireMock.Owin.Mappers;
@@ -22,7 +24,7 @@ namespace WireMock.Owin.Mappers;
internal class OwinRequestMapper : IOwinRequestMapper
{
/// <inheritdoc />
public async Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options)
public async Task<RequestMessage> MapAsync(HttpRequest request, IWireMockMiddlewareOptions options)
{
var (urlDetails, clientIP) = ParseRequest(request);
@@ -83,12 +85,12 @@ internal class OwinRequestMapper : IOwinRequestMapper
};
}
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(IRequest request)
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(HttpRequest request)
{
#if !USE_ASPNETCORE
var urlDetails = UrlUtils.Parse(request.Uri, request.PathBase);
var clientIP = request.RemoteIpAddress;
#else
//#if !USE_ASPNETCORE
// var urlDetails = UrlUtils.Parse(request.Uri, request.PathBase);
// var clientIP = request.RemoteIpAddress;
//#else
var urlDetails = UrlUtils.Parse(new Uri(request.GetEncodedUrl()), request.PathBase);
var connection = request.HttpContext.Connection;
@@ -105,7 +107,7 @@ internal class OwinRequestMapper : IOwinRequestMapper
{
clientIP = connection.RemoteIpAddress.ToString();
}
#endif
//#endif
return (urlDetails, clientIP);
}
}

View File

@@ -8,21 +8,22 @@ using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using RandomDataGenerator.FieldOptions;
using RandomDataGenerator.Randomizers;
using Stef.Validation;
using WireMock.Http;
using WireMock.ResponseBuilders;
using WireMock.Types;
using Stef.Validation;
using WireMock.Util;
#if !USE_ASPNETCORE
using IResponse = Microsoft.Owin.IOwinResponse;
#else
using Microsoft.AspNetCore.Http;
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
#endif
//#if !USE_ASPNETCORE
//using IResponse = Microsoft.Owin.IOwinResponse;
//#else
//using Microsoft.AspNetCore.Http;
//using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
//#endif
namespace WireMock.Owin.Mappers
{
@@ -37,8 +38,8 @@ namespace WireMock.Owin.Mappers
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
private static readonly IDictionary<string, Action<IResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
new Dictionary<string, Action<IResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
private static readonly IDictionary<string, Action<HttpResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
new Dictionary<string, Action<HttpResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
{
{ HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() },
{ HttpKnownHeaderNames.ContentLength, (r, hasBody, v) =>
@@ -62,7 +63,7 @@ namespace WireMock.Owin.Mappers
}
/// <inheritdoc />
public async Task MapAsync(IResponseMessage? responseMessage, IResponse response)
public async Task MapAsync(IResponseMessage? responseMessage, HttpResponse response)
{
if (responseMessage == null)
{
@@ -128,7 +129,7 @@ namespace WireMock.Owin.Mappers
SetResponseTrailingHeaders(responseMessage, response);
}
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, IResponse response, IBodyData bodyData)
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, HttpResponse response, IBodyData bodyData)
{
if (bodyData.SseStringQueue == null)
{
@@ -199,7 +200,7 @@ namespace WireMock.Owin.Mappers
return null;
}
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, IResponse response)
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, HttpResponse response)
{
// Force setting the Date header (#577)
AppendResponseHeader(
@@ -215,7 +216,7 @@ namespace WireMock.Owin.Mappers
var value = item.Value;
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
{
action?.Invoke(response, hasBody, value);
action.Invoke(response, hasBody, value);
}
else
{
@@ -228,7 +229,7 @@ namespace WireMock.Owin.Mappers
}
}
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, IResponse response)
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, HttpResponse response)
{
if (responseMessage.TrailingHeaders == null)
{
@@ -236,13 +237,11 @@ namespace WireMock.Owin.Mappers
}
#if TRAILINGHEADERS
foreach (var item in responseMessage.TrailingHeaders)
foreach (var (headerName, value) in responseMessage.TrailingHeaders)
{
var headerName = item.Key;
var value = item.Value;
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
{
action?.Invoke(response, false, value);
action.Invoke(response, false, value);
}
else
{
@@ -256,13 +255,13 @@ namespace WireMock.Owin.Mappers
#endif
}
private static void AppendResponseHeader(IResponse response, string headerName, string[] values)
private static void AppendResponseHeader(HttpResponse response, string headerName, string[] values)
{
#if !USE_ASPNETCORE
response.Headers.AppendValues(headerName, values);
#else
//#if !USE_ASPNETCORE
// response.Headers.AppendValues(headerName, values);
//#else
response.Headers.Append(headerName, values);
#endif
//#endif
}
}
}

View File

@@ -1,114 +1,112 @@
// Copyright © WireMock.Net
#if !USE_ASPNETCORE
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Logging;
using WireMock.Owin.Mappers;
using Stef.Validation;
using WireMock.Services;
using WireMock.Util;
//using Microsoft.Owin.Hosting;
//using Owin;
//using System;
//using System.Collections.Generic;
//using System.Threading;
//using System.Threading.Tasks;
//using JetBrains.Annotations;
//using WireMock.Logging;
//using WireMock.Owin.Mappers;
//using Stef.Validation;
//using WireMock.Services;
//using WireMock.Util;
namespace WireMock.Owin;
//namespace WireMock.Owin;
internal class OwinSelfHost : IOwinSelfHost
{
private readonly IWireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new();
private readonly IWireMockLogger _logger;
//internal class OwinSelfHost : IOwinSelfHost
//{
// private readonly IWireMockMiddlewareOptions _options;
// private readonly CancellationTokenSource _cts = new();
// private readonly IWireMockLogger _logger;
private Exception? _runningException;
// private Exception? _runningException;
public OwinSelfHost(IWireMockMiddlewareOptions options, HostUrlOptions urlOptions)
{
Guard.NotNull(urlOptions);
// public OwinSelfHost(IWireMockMiddlewareOptions options, HostUrlOptions urlOptions)
// {
// Guard.NotNull(urlOptions);
_options = Guard.NotNull(options);
_logger = options.Logger ?? new WireMockConsoleLogger();
// _options = Guard.NotNull(options);
// _logger = options.Logger ?? new WireMockConsoleLogger();
foreach (var detail in urlOptions.GetDetails())
{
Urls.Add(detail.Url);
Ports.Add(detail.Port);
}
}
// 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; }
public List<string> Urls { get; } = new();
// public List<string> Urls { get; } = new();
public List<int> Ports { get; } = new();
// public List<int> Ports { get; } = new();
public Exception? RunningException => _runningException;
// public Exception? RunningException => _runningException;
[PublicAPI]
public Task StartAsync()
{
return Task.Run(StartServers, _cts.Token);
}
// [PublicAPI]
// public Task StartAsync()
// {
// return Task.Run(StartServers, _cts.Token);
// }
[PublicAPI]
public Task StopAsync()
{
_cts.Cancel();
// [PublicAPI]
// public Task StopAsync()
// {
// _cts.Cancel();
return Task.FromResult(true);
}
// return Task.FromResult(true);
// }
private void StartServers()
{
#if NET46
_logger.Info("Server using .net 4.6");
#else
_logger.Info("Server using .net 4.5.x");
#endif
var servers = new List<IDisposable>();
// private void StartServers()
// {
//#if NET46
// _logger.Info("Server using .net 4.6");
//#else
// _logger.Info("Server using .net 4.5.x");
//#endif
// var servers = new List<IDisposable>();
try
{
var requestMapper = new OwinRequestMapper();
var responseMapper = new OwinResponseMapper(_options);
var matcher = new MappingMatcher(_options, new RandomizerDoubleBetween0And1());
var guidUtils = new GuidUtils();
// try
// {
// var requestMapper = new OwinRequestMapper();
// var responseMapper = new OwinResponseMapper(_options);
// var matcher = new MappingMatcher(_options, new RandomizerDoubleBetween0And1());
// var guidUtils = new GuidUtils();
Action<IAppBuilder> startup = app =>
{
app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher, guidUtils);
_options.PostWireMockMiddlewareInit?.Invoke(app);
};
// Action<IAppBuilder> startup = app =>
// {
// app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
// _options.PreWireMockMiddlewareInit?.Invoke(app);
// app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher, guidUtils);
// _options.PostWireMockMiddlewareInit?.Invoke(app);
// };
foreach (var url in Urls)
{
servers.Add(WebApp.Start(url, startup));
}
// foreach (var url in Urls)
// {
// servers.Add(WebApp.Start(url, startup));
// }
IsStarted = true;
// IsStarted = true;
// WaitHandle is signaled when the token is cancelled,
// which will be more efficient than Thread.Sleep in while loop
_cts.Token.WaitHandle.WaitOne();
}
catch (Exception e)
{
// 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;
// Dispose all servers in finally block to make sure clean up allocated resource on error happening
servers.ForEach(s => s.Dispose());
}
}
}
#endif
// // WaitHandle is signaled when the token is cancelled,
// // which will be more efficient than Thread.Sleep in while loop
// _cts.Token.WaitHandle.WaitOne();
// }
// catch (Exception e)
// {
// // 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;
// // Dispose all servers in finally block to make sure clean up allocated resource on error happening
// servers.ForEach(s => s.Dispose());
// }
// }
//}

View File

@@ -1,368 +1,368 @@
// Copyright © WireMock.Net
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Stef.Validation;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Http;
using WireMock.Owin.Mappers;
using WireMock.Serialization;
using WireMock.ResponseBuilders;
using WireMock.Settings;
using System.Collections.Generic;
using WireMock.Constants;
using WireMock.Exceptions;
using WireMock.Http;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Owin.Mappers;
using WireMock.ResponseBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Util;
#if !USE_ASPNETCORE
using IContext = Microsoft.Owin.IOwinContext;
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
using Next = Microsoft.Owin.OwinMiddleware;
#else
using OwinMiddleware = System.Object;
using IContext = Microsoft.AspNetCore.Http.HttpContext;
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
#endif
//#if !USE_ASPNETCORE
//using IContext = Microsoft.Owin.IOwinContext;
//using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
//using Next = Microsoft.Owin.OwinMiddleware;
//#else
//using OwinMiddleware = System.Object;
//using IContext = Microsoft.AspNetCore.Http.HttpContext;
//using Next = Microsoft.AspNetCore.Http.RequestDelegate;
//#endif
namespace WireMock.Owin
namespace WireMock.Owin;
internal class WireMockMiddleware //: OwinMiddleware
{
internal class WireMockMiddleware : OwinMiddleware
private readonly object _lock = new();
private static readonly Task CompletedTask = Task.FromResult(false);
private readonly IWireMockMiddlewareOptions _options;
private readonly IOwinRequestMapper _requestMapper;
private readonly IOwinResponseMapper _responseMapper;
private readonly IMappingMatcher _mappingMatcher;
private readonly LogEntryMapper _logEntryMapper;
private readonly IGuidUtils _guidUtils;
//#if !USE_ASPNETCORE
// public WireMockMiddleware(
// Next next,
// IWireMockMiddlewareOptions options,
// IOwinRequestMapper requestMapper,
// IOwinResponseMapper responseMapper,
// IMappingMatcher mappingMatcher,
// IGuidUtils guidUtils
// ) : base(next)
// {
// _options = Guard.NotNull(options);
// _requestMapper = Guard.NotNull(requestMapper);
// _responseMapper = Guard.NotNull(responseMapper);
// _mappingMatcher = Guard.NotNull(mappingMatcher);
// _logEntryMapper = new LogEntryMapper(options);
// _guidUtils = Guard.NotNull(guidUtils);
// }
//#else
public WireMockMiddleware(
RequestDelegate next,
IWireMockMiddlewareOptions options,
IOwinRequestMapper requestMapper,
IOwinResponseMapper responseMapper,
IMappingMatcher mappingMatcher,
IGuidUtils guidUtils
)
{
private readonly object _lock = new();
private static readonly Task CompletedTask = Task.FromResult(false);
_options = Guard.NotNull(options);
_requestMapper = Guard.NotNull(requestMapper);
_responseMapper = Guard.NotNull(responseMapper);
_mappingMatcher = Guard.NotNull(mappingMatcher);
_logEntryMapper = new LogEntryMapper(options);
_guidUtils = Guard.NotNull(guidUtils);
}
//#endif
private readonly IWireMockMiddlewareOptions _options;
private readonly IOwinRequestMapper _requestMapper;
private readonly IOwinResponseMapper _responseMapper;
private readonly IMappingMatcher _mappingMatcher;
private readonly LogEntryMapper _logEntryMapper;
private readonly IGuidUtils _guidUtils;
#if !USE_ASPNETCORE
public WireMockMiddleware(
Next next,
IWireMockMiddlewareOptions options,
IOwinRequestMapper requestMapper,
IOwinResponseMapper responseMapper,
IMappingMatcher mappingMatcher,
IGuidUtils guidUtils
) : base(next)
//#if !USE_ASPNETCORE
// public override Task Invoke(IContext ctx)
//#else
public Task Invoke(HttpContext ctx)
//#endif
{
if (_options.HandleRequestsSynchronously.GetValueOrDefault(false))
{
_options = Guard.NotNull(options);
_requestMapper = Guard.NotNull(requestMapper);
_responseMapper = Guard.NotNull(responseMapper);
_mappingMatcher = Guard.NotNull(mappingMatcher);
_logEntryMapper = new LogEntryMapper(options);
_guidUtils = Guard.NotNull(guidUtils);
}
#else
public WireMockMiddleware(
Next next,
IWireMockMiddlewareOptions options,
IOwinRequestMapper requestMapper,
IOwinResponseMapper responseMapper,
IMappingMatcher mappingMatcher,
IGuidUtils guidUtils
)
{
_options = Guard.NotNull(options);
_requestMapper = Guard.NotNull(requestMapper);
_responseMapper = Guard.NotNull(responseMapper);
_mappingMatcher = Guard.NotNull(mappingMatcher);
_logEntryMapper = new LogEntryMapper(options);
_guidUtils = Guard.NotNull(guidUtils);
}
#endif
#if !USE_ASPNETCORE
public override Task Invoke(IContext ctx)
#else
public Task Invoke(IContext ctx)
#endif
{
if (_options.HandleRequestsSynchronously.GetValueOrDefault(false))
lock (_lock)
{
lock (_lock)
return InvokeInternalAsync(ctx);
}
}
return InvokeInternalAsync(ctx);
}
private async Task InvokeInternalAsync(HttpContext ctx)
{
var request = await _requestMapper.MapAsync(ctx.Request, _options).ConfigureAwait(false);
var logRequest = false;
IResponseMessage? response = null;
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
try
{
foreach (var mapping in _options.Mappings.Values)
{
if (mapping.Scenario is null)
{
return InvokeInternalAsync(ctx);
continue;
}
// Set scenario start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{
_options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
{
Name = mapping.Scenario
});
}
}
return InvokeInternalAsync(ctx);
}
result = _mappingMatcher.FindBestMatch(request);
private async Task InvokeInternalAsync(IContext ctx)
{
var request = await _requestMapper.MapAsync(ctx.Request, _options).ConfigureAwait(false);
var logRequest = false;
IResponseMessage? response = null;
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
try
var targetMapping = result.Match?.Mapping;
if (targetMapping == null)
{
foreach (var mapping in _options.Mappings.Values)
logRequest = true;
_options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
return;
}
logRequest = targetMapping.LogMapping;
if (targetMapping.IsAdminInterface && _options.AuthenticationMatcher != null && request.Headers != null)
{
var authorizationHeaderPresent = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out var authorization);
if (!authorizationHeaderPresent)
{
if (mapping.Scenario is null)
{
continue;
}
// Set scenario start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{
_options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
{
Name = mapping.Scenario
});
}
}
result = _mappingMatcher.FindBestMatch(request);
var targetMapping = result.Match?.Mapping;
if (targetMapping == null)
{
logRequest = true;
_options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
_options.Logger.Error("HttpStatusCode set to 401, authorization header is missing.");
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
return;
}
logRequest = targetMapping.LogMapping;
if (targetMapping.IsAdminInterface && _options.AuthenticationMatcher != null && request.Headers != null)
var authorizationHeaderMatchResult = _options.AuthenticationMatcher.IsMatch(authorization!.ToString());
if (!MatchScores.IsPerfect(authorizationHeaderMatchResult.Score))
{
var authorizationHeaderPresent = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out var authorization);
if (!authorizationHeaderPresent)
{
_options.Logger.Error("HttpStatusCode set to 401, authorization header is missing.");
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
return;
}
_options.Logger.Error("HttpStatusCode set to 401, authentication failed.", authorizationHeaderMatchResult.Exception ?? throw new WireMockException("Authentication failed"));
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
return;
}
}
var authorizationHeaderMatchResult = _options.AuthenticationMatcher.IsMatch(authorization!.ToString());
if (!MatchScores.IsPerfect(authorizationHeaderMatchResult.Score))
{
_options.Logger.Error("HttpStatusCode set to 401, authentication failed.", authorizationHeaderMatchResult.Exception ?? throw new WireMockException("Authentication failed"));
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
return;
}
if (!targetMapping.IsAdminInterface && _options.RequestProcessingDelay > TimeSpan.Zero)
{
await Task.Delay(_options.RequestProcessingDelay.Value).ConfigureAwait(false);
}
var (theResponse, theOptionalNewMapping) = await targetMapping.ProvideResponseAsync(request).ConfigureAwait(false);
response = theResponse;
var responseBuilder = targetMapping.Provider as Response;
if (!targetMapping.IsAdminInterface && theOptionalNewMapping != null)
{
if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMapping == true)
{
_options.Mappings.TryAdd(theOptionalNewMapping.Guid, theOptionalNewMapping);
}
if (!targetMapping.IsAdminInterface && _options.RequestProcessingDelay > TimeSpan.Zero)
if (responseBuilder?.ProxyAndRecordSettings?.SaveMappingToFile == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMappingToFile == true)
{
await Task.Delay(_options.RequestProcessingDelay.Value).ConfigureAwait(false);
var matcherMapper = new MatcherMapper(targetMapping.Settings);
var mappingConverter = new MappingConverter(matcherMapper);
var mappingToFileSaver = new MappingToFileSaver(targetMapping.Settings, mappingConverter);
mappingToFileSaver.SaveMappingToFile(theOptionalNewMapping);
}
}
var (theResponse, theOptionalNewMapping) = await targetMapping.ProvideResponseAsync(request).ConfigureAwait(false);
response = theResponse;
if (targetMapping.Scenario != null)
{
UpdateScenarioState(targetMapping);
}
var responseBuilder = targetMapping.Provider as Response;
if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0)
{
await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false);
}
}
catch (Exception ex)
{
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
response = ResponseMessageBuilder.Create(500, ex.Message);
}
finally
{
var log = new LogEntry
{
Guid = _guidUtils.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
if (!targetMapping.IsAdminInterface && theOptionalNewMapping != null)
MappingGuid = result.Match?.Mapping?.Guid,
MappingTitle = result.Match?.Mapping?.Title,
RequestMatchResult = result.Match?.RequestMatchResult,
PartialMappingGuid = result.Partial?.Mapping?.Guid,
PartialMappingTitle = result.Partial?.Mapping?.Title,
PartialMatchResult = result.Partial?.RequestMatchResult
};
LogRequest(log, logRequest);
try
{
if (_options.SaveUnmatchedRequests == true && result.Match?.RequestMatchResult is not { IsPerfectMatch: true })
{
if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMapping == true)
{
_options.Mappings.TryAdd(theOptionalNewMapping.Guid, theOptionalNewMapping);
}
if (responseBuilder?.ProxyAndRecordSettings?.SaveMappingToFile == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMappingToFile == true)
{
var matcherMapper = new MatcherMapper(targetMapping.Settings);
var mappingConverter = new MappingConverter(matcherMapper);
var mappingToFileSaver = new MappingToFileSaver(targetMapping.Settings, mappingConverter);
mappingToFileSaver.SaveMappingToFile(theOptionalNewMapping);
}
var filename = $"{log.Guid}.LogEntry.json";
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(log));
}
}
catch
{
// Empty catch
}
if (targetMapping.Scenario != null)
{
UpdateScenarioState(targetMapping);
}
if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0)
{
await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false);
}
try
{
await _responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false);
}
catch (Exception ex)
{
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
response = ResponseMessageBuilder.Create(500, ex.Message);
_options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex);
var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
await _responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false);
}
finally
}
await CompletedTask.ConfigureAwait(false);
}
private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response)
{
var tasks = new List<Func<Task>>();
for (int index = 0; index < mapping.Webhooks?.Length; index++)
{
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
var webhookSender = new WebhookSender(mapping.Settings);
var webhookRequest = mapping.Webhooks[index].Request;
var webHookIndex = index;
tasks.Add(async () =>
{
var log = new LogEntry
{
Guid = _guidUtils.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
MappingGuid = result.Match?.Mapping?.Guid,
MappingTitle = result.Match?.Mapping?.Title,
RequestMatchResult = result.Match?.RequestMatchResult,
PartialMappingGuid = result.Partial?.Mapping?.Guid,
PartialMappingTitle = result.Partial?.Mapping?.Title,
PartialMatchResult = result.Partial?.RequestMatchResult
};
LogRequest(log, logRequest);
try
{
if (_options.SaveUnmatchedRequests == true && result.Match?.RequestMatchResult is not { IsPerfectMatch: true })
var result = await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
if (!result.IsSuccessStatusCode)
{
var filename = $"{log.Guid}.LogEntry.json";
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(log));
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
_options.Logger.Warn($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. HttpStatusCode: {result.StatusCode} Content: {content}");
}
}
catch
{
// Empty catch
}
try
{
await _responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false);
}
catch (Exception ex)
{
_options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex);
var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
await _responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false);
_options.Logger.Error($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
}
}
await CompletedTask.ConfigureAwait(false);
});
}
private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response)
if (mapping.UseWebhooksFireAndForget == true)
{
var tasks = new List<Func<Task>>();
for (int index = 0; index < mapping.Webhooks?.Length; index++)
try
{
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
var webhookSender = new WebhookSender(mapping.Settings);
var webhookRequest = mapping.Webhooks[index].Request;
var webHookIndex = index;
tasks.Add(async () =>
// Do not wait
await Task.Run(() =>
{
try
{
var result = await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
if (!result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
_options.Logger.Warn($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. HttpStatusCode: {result.StatusCode} Content: {content}");
}
}
catch (Exception ex)
{
_options.Logger.Error($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
}
Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
});
}
if (mapping.UseWebhooksFireAndForget == true)
{
try
{
// Do not wait
await Task.Run(() =>
{
Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
});
}
catch
{
// Ignore
}
}
else
{
await Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
}
}
private void UpdateScenarioState(IMapping mapping)
{
var scenario = _options.Scenarios[mapping.Scenario!];
// Increase the number of times this state has been executed
scenario.Counter++;
// Only if the number of times this state is executed equals the required StateTimes, proceed to next state and reset the counter to 0
if (scenario.Counter == (mapping.TimesInSameState ?? 1))
{
scenario.NextState = mapping.NextState;
scenario.Counter = 0;
}
// Else just update Started and Finished
scenario.Started = true;
scenario.Finished = mapping.NextState == null;
}
private void LogRequest(LogEntry entry, bool addRequest)
{
_options.Logger.DebugRequestResponse(_logEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));
// If addRequest is set to true and MaxRequestLogCount is null or does have a value greater than 0, try to add a new request log.
if (addRequest && _options.MaxRequestLogCount is null or > 0)
{
TryAddLogEntry(entry);
}
// In case MaxRequestLogCount has a value greater than 0, try to delete existing request logs based on the count.
if (_options.MaxRequestLogCount is > 0)
{
var logEntries = _options.LogEntries.ToList();
foreach (var logEntry in logEntries.OrderBy(le => le.RequestMessage.DateTime).Take(logEntries.Count - _options.MaxRequestLogCount.Value))
{
TryRemoveLogEntry(logEntry);
}
}
// In case RequestLogExpirationDuration has a value greater than 0, try to delete existing request logs based on the date.
if (_options.RequestLogExpirationDuration is > 0)
{
var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value);
foreach (var logEntry in _options.LogEntries.ToList().Where(le => le.RequestMessage.DateTime < checkTime))
{
TryRemoveLogEntry(logEntry);
}
}
}
private void TryAddLogEntry(LogEntry logEntry)
{
try
{
_options.LogEntries.Add(logEntry);
}
catch
{
// Ignore exception (can happen during stress testing)
// Ignore
}
}
else
{
await Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
}
}
private void UpdateScenarioState(IMapping mapping)
{
var scenario = _options.Scenarios[mapping.Scenario!];
// Increase the number of times this state has been executed
scenario.Counter++;
// Only if the number of times this state is executed equals the required StateTimes, proceed to next state and reset the counter to 0
if (scenario.Counter == (mapping.TimesInSameState ?? 1))
{
scenario.NextState = mapping.NextState;
scenario.Counter = 0;
}
// Else just update Started and Finished
scenario.Started = true;
scenario.Finished = mapping.NextState == null;
}
private void LogRequest(LogEntry entry, bool addRequest)
{
_options.Logger.DebugRequestResponse(_logEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));
// If addRequest is set to true and MaxRequestLogCount is null or does have a value greater than 0, try to add a new request log.
if (addRequest && _options.MaxRequestLogCount is null or > 0)
{
TryAddLogEntry(entry);
}
// In case MaxRequestLogCount has a value greater than 0, try to delete existing request logs based on the count.
if (_options.MaxRequestLogCount is > 0)
{
var logEntries = _options.LogEntries.ToList();
foreach (var logEntry in logEntries.OrderBy(le => le.RequestMessage.DateTime).Take(logEntries.Count - _options.MaxRequestLogCount.Value))
{
TryRemoveLogEntry(logEntry);
}
}
private void TryRemoveLogEntry(LogEntry logEntry)
// In case RequestLogExpirationDuration has a value greater than 0, try to delete existing request logs based on the date.
if (_options.RequestLogExpirationDuration is > 0)
{
try
var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value);
foreach (var logEntry in _options.LogEntries.ToList().Where(le => le.RequestMessage.DateTime < checkTime))
{
_options.LogEntries.Remove(logEntry);
}
catch
{
// Ignore exception (can happen during stress testing)
TryRemoveLogEntry(logEntry);
}
}
}
}
private void TryAddLogEntry(LogEntry logEntry)
{
try
{
_options.LogEntries.Add(logEntry);
}
catch
{
// Ignore exception (can happen during stress testing)
}
}
private void TryRemoveLogEntry(LogEntry logEntry)
{
try
{
_options.LogEntries.Remove(logEntry);
}
catch
{
// Ignore exception (can happen during stress testing)
}
}
}

View File

@@ -8,13 +8,17 @@ using WireMock.Matchers;
using WireMock.Types;
using WireMock.Util;
using System.Security.Cryptography.X509Certificates;
#if !USE_ASPNETCORE
using Owin;
#else
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.DependencyInjection;
#endif
using ClientCertificateMode = Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode;
//#if !USE_ASPNETCORE
//using Owin;
//#else
//using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
//using Microsoft.Extensions.DependencyInjection;
//#endif
namespace WireMock.Owin;
@@ -38,11 +42,11 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
public int? MaxRequestLogCount { get; set; }
public Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
public Action<IApplicationBuilder>? PreWireMockMiddlewareInit { get; set; }
public Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
public Action<IApplicationBuilder>? PostWireMockMiddlewareInit { get; set; }
#if USE_ASPNETCORE
//#if USE_ASPNETCORE
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
@@ -51,7 +55,7 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
/// <inheritdoc />
public bool AcceptAnyClientCertificate { get; set; }
#endif
//#endif
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
public IFileSystemHandler? FileSystemHandler { get; set; }