mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-26 11:21:51 +01:00
mm
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock.Extensions;
|
||||
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
public static bool TryGetStringValue(this IDictionary dictionary, string key, [NotNullWhen(true)] out string? value)
|
||||
{
|
||||
Guard.NotNull(dictionary);
|
||||
|
||||
if (dictionary[key] is string valueIsString)
|
||||
{
|
||||
value = valueIsString;
|
||||
return true;
|
||||
}
|
||||
|
||||
var valueToString = dictionary[key]?.ToString();
|
||||
if (valueToString != null)
|
||||
{
|
||||
value = valueToString;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Owin.ActivityTracing;
|
||||
|
||||
/// <summary>
|
||||
/// Provides an ActivitySource for WireMock.Net distributed tracing.
|
||||
/// </summary>
|
||||
public static class WireMockActivitySource
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the ActivitySource used by WireMock.Net.
|
||||
/// </summary>
|
||||
internal const string SourceName = "WireMock.Net";
|
||||
|
||||
/// <summary>
|
||||
/// The ActivitySource instance used for creating tracing activities.
|
||||
/// </summary>
|
||||
public static readonly ActivitySource Source = new(SourceName, GetVersion());
|
||||
|
||||
private static string GetVersion()
|
||||
{
|
||||
return typeof(WireMockActivitySource).Assembly.GetName().Version?.ToString() ?? "1.0.0";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new activity for a WireMock request.
|
||||
/// </summary>
|
||||
/// <param name="requestMethod">The HTTP method of the request.</param>
|
||||
/// <param name="requestPath">The path of the request.</param>
|
||||
/// <returns>The started activity, or null if tracing is not enabled.</returns>
|
||||
internal static Activity? StartRequestActivity(string requestMethod, string requestPath)
|
||||
{
|
||||
if (!Source.HasListeners())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var activity = Source.StartActivity(
|
||||
$"WireMock {requestMethod} {requestPath}",
|
||||
ActivityKind.Server
|
||||
);
|
||||
|
||||
return activity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enriches an activity with request information.
|
||||
/// </summary>
|
||||
internal static void EnrichWithRequest(Activity? activity, IRequestMessage request, ActivityTracingOptions? options = null)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activity.SetTag(WireMockSemanticConventions.HttpMethod, request.Method);
|
||||
activity.SetTag(WireMockSemanticConventions.HttpUrl, request.Url);
|
||||
activity.SetTag(WireMockSemanticConventions.HttpPath, request.Path);
|
||||
activity.SetTag(WireMockSemanticConventions.HttpHost, request.Host);
|
||||
|
||||
if (request.ClientIP != null)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.ClientAddress, request.ClientIP);
|
||||
}
|
||||
|
||||
// Record request body if enabled
|
||||
if (options?.RecordRequestBody == true && request.Body != null)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.RequestBody, request.Body);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enriches an activity with response information.
|
||||
/// </summary>
|
||||
internal static void EnrichWithResponse(Activity? activity, IResponseMessage? response, ActivityTracingOptions? options = null)
|
||||
{
|
||||
if (activity == null || response == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// StatusCode can be int, HttpStatusCode, or string
|
||||
var statusCode = response.StatusCode;
|
||||
int? statusCodeInt = statusCode switch
|
||||
{
|
||||
int i => i,
|
||||
System.Net.HttpStatusCode hsc => (int)hsc,
|
||||
string s when int.TryParse(s, out var parsed) => parsed,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (statusCodeInt.HasValue)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.HttpStatusCode, statusCodeInt.Value);
|
||||
activity.SetTag("otel.status_description", $"HTTP {statusCodeInt.Value}");
|
||||
|
||||
// Set status based on HTTP status code (using standard otel.status_code tag)
|
||||
if (statusCodeInt.Value >= 400)
|
||||
{
|
||||
activity.SetTag("otel.status_code", "ERROR");
|
||||
}
|
||||
else
|
||||
{
|
||||
activity.SetTag("otel.status_code", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
// Record response body if enabled
|
||||
if (options?.RecordResponseBody == true && response.BodyData?.BodyAsString != null)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.ResponseBody, response.BodyData.BodyAsString);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enriches an activity with mapping match information.
|
||||
/// </summary>
|
||||
internal static void EnrichWithMappingMatch(
|
||||
Activity? activity,
|
||||
Guid? mappingGuid,
|
||||
string? mappingTitle,
|
||||
bool isPerfectMatch,
|
||||
double? matchScore)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activity.SetTag(WireMockSemanticConventions.MappingMatched, isPerfectMatch);
|
||||
|
||||
if (mappingGuid.HasValue)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.MappingGuid, mappingGuid.Value.ToString());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(mappingTitle))
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.MappingTitle, mappingTitle);
|
||||
}
|
||||
|
||||
if (matchScore.HasValue)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.MatchScore, matchScore.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enriches an activity with log entry information (includes response and mapping match info).
|
||||
/// </summary>
|
||||
internal static void EnrichWithLogEntry(Activity? activity, ILogEntry logEntry, ActivityTracingOptions? options = null)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Enrich with response
|
||||
EnrichWithResponse(activity, logEntry.ResponseMessage, options);
|
||||
|
||||
// Enrich with mapping match (if enabled)
|
||||
if (options?.RecordMatchDetails != false)
|
||||
{
|
||||
EnrichWithMappingMatch(
|
||||
activity,
|
||||
logEntry.MappingGuid,
|
||||
logEntry.MappingTitle,
|
||||
logEntry.RequestMatchResult?.IsPerfectMatch ?? false,
|
||||
logEntry.RequestMatchResult?.TotalScore);
|
||||
}
|
||||
|
||||
// Set request GUID
|
||||
activity.SetTag(WireMockSemanticConventions.RequestGuid, logEntry.Guid.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Records an exception on the activity.
|
||||
/// </summary>
|
||||
internal static void RecordException(Activity? activity, Exception exception)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Use standard OpenTelemetry exception semantic conventions
|
||||
activity.SetTag("otel.status_code", "ERROR");
|
||||
activity.SetTag("otel.status_description", exception.Message);
|
||||
activity.SetTag("exception.type", exception.GetType().FullName);
|
||||
activity.SetTag("exception.message", exception.Message);
|
||||
activity.SetTag("exception.stacktrace", exception.ToString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
namespace WireMock.Owin.ActivityTracing;
|
||||
|
||||
/// <summary>
|
||||
/// Semantic convention constants for WireMock.Net tracing attributes.
|
||||
/// </summary>
|
||||
internal static class WireMockSemanticConventions
|
||||
{
|
||||
// Standard HTTP semantic conventions (OpenTelemetry)
|
||||
public const string HttpMethod = "http.request.method";
|
||||
public const string HttpUrl = "url.full";
|
||||
public const string HttpPath = "url.path";
|
||||
public const string HttpHost = "server.address";
|
||||
public const string HttpStatusCode = "http.response.status_code";
|
||||
public const string ClientAddress = "client.address";
|
||||
|
||||
// WireMock-specific attributes
|
||||
public const string MappingMatched = "wiremock.mapping.matched";
|
||||
public const string MappingGuid = "wiremock.mapping.guid";
|
||||
public const string MappingTitle = "wiremock.mapping.title";
|
||||
public const string MatchScore = "wiremock.match.score";
|
||||
public const string PartialMappingGuid = "wiremock.partial_mapping.guid";
|
||||
public const string PartialMappingTitle = "wiremock.partial_mapping.title";
|
||||
public const string RequestGuid = "wiremock.request.guid";
|
||||
public const string RequestBody = "wiremock.request.body";
|
||||
public const string ResponseBody = "wiremock.response.body";
|
||||
}
|
||||
@@ -8,17 +8,11 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
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;
|
||||
|
||||
internal interface IWireMockMiddlewareOptions
|
||||
@@ -45,7 +39,6 @@ internal interface IWireMockMiddlewareOptions
|
||||
|
||||
Action<IApplicationBuilder>? PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
//#if USE_ASPNETCORE
|
||||
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||
|
||||
CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||
@@ -53,7 +46,6 @@ internal interface IWireMockMiddlewareOptions
|
||||
ClientCertificateMode ClientCertificateMode { get; set; }
|
||||
|
||||
bool AcceptAnyClientCertificate { get; set; }
|
||||
//#endif
|
||||
|
||||
IFileSystemHandler? FileSystemHandler { get; set; }
|
||||
|
||||
@@ -91,4 +83,10 @@ internal interface IWireMockMiddlewareOptions
|
||||
QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
||||
|
||||
public bool ProxyAll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activity tracing options.
|
||||
/// When set, System.Diagnostics.Activity objects are created for request tracing.
|
||||
/// </summary>
|
||||
ActivityTracingOptions? ActivityTracingOptions { get; set; }
|
||||
}
|
||||
@@ -17,19 +17,12 @@ 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
|
||||
using System.Diagnostics;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class WireMockMiddleware //: OwinMiddleware
|
||||
internal class WireMockMiddleware
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private static readonly Task CompletedTask = Task.FromResult(false);
|
||||
@@ -41,24 +34,6 @@ internal class WireMockMiddleware //: OwinMiddleware
|
||||
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,
|
||||
@@ -75,13 +50,8 @@ internal class WireMockMiddleware //: OwinMiddleware
|
||||
_logEntryMapper = new LogEntryMapper(options);
|
||||
_guidUtils = Guard.NotNull(guidUtils);
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#if !USE_ASPNETCORE
|
||||
// public override Task Invoke(IContext ctx)
|
||||
//#else
|
||||
public Task Invoke(HttpContext ctx)
|
||||
//#endif
|
||||
{
|
||||
if (_options.HandleRequestsSynchronously.GetValueOrDefault(false))
|
||||
{
|
||||
@@ -102,6 +72,19 @@ internal class WireMockMiddleware //: OwinMiddleware
|
||||
IResponseMessage? response = null;
|
||||
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
|
||||
|
||||
var tracingEnabled = _options.ActivityTracingOptions is not null;
|
||||
var excludeAdmin = _options.ActivityTracingOptions?.ExcludeAdminRequests ?? true;
|
||||
Activity? activity = null;
|
||||
|
||||
// Check if we should trace this request (optionally exclude admin requests)
|
||||
var shouldTrace = tracingEnabled && !(excludeAdmin && request.Path.StartsWith("/__admin/"));
|
||||
|
||||
if (shouldTrace)
|
||||
{
|
||||
activity = WireMockActivitySource.StartRequestActivity(request.Method, request.Path);
|
||||
WireMockActivitySource.EnrichWithRequest(activity, request, _options.ActivityTracingOptions);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var mapping in _options.Mappings.Values)
|
||||
@@ -193,6 +176,8 @@ internal class WireMockMiddleware //: OwinMiddleware
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
|
||||
WireMockActivitySource.RecordException(activity, ex);
|
||||
|
||||
response = ResponseMessageBuilder.Create(500, ex.Message);
|
||||
}
|
||||
finally
|
||||
@@ -212,6 +197,9 @@ internal class WireMockMiddleware //: OwinMiddleware
|
||||
PartialMatchResult = result.Partial?.RequestMatchResult
|
||||
};
|
||||
|
||||
WireMockActivitySource.EnrichWithLogEntry(activity, log, _options.ActivityTracingOptions);
|
||||
activity?.Dispose();
|
||||
|
||||
LogRequest(log, logRequest);
|
||||
|
||||
try
|
||||
|
||||
@@ -2,24 +2,18 @@
|
||||
|
||||
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.Owin.ActivityTracing;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
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;
|
||||
|
||||
internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
@@ -110,4 +104,7 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ProxyAll { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ActivityTracingOptions? ActivityTracingOptions { get; set; }
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
@@ -18,6 +19,7 @@ internal static class WireMockMiddlewareOptionsHelper
|
||||
|
||||
options ??= new WireMockMiddlewareOptions();
|
||||
|
||||
options.ActivityTracingOptions = settings.ActivityTracingOptions;
|
||||
options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods;
|
||||
options.AllowOnlyDefinedHttpStatusCodeInResponse = settings.AllowOnlyDefinedHttpStatusCodeInResponse;
|
||||
options.AllowPartialMapping = settings.AllowPartialMapping;
|
||||
@@ -34,6 +36,13 @@ internal static class WireMockMiddlewareOptionsHelper
|
||||
options.RequestLogExpirationDuration = settings.RequestLogExpirationDuration;
|
||||
options.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
options.AdditionalServiceRegistration = settings.AdditionalServiceRegistration;
|
||||
options.CorsPolicyOptions = settings.CorsPolicyOptions;
|
||||
options.ClientCertificateMode = settings.ClientCertificateMode;
|
||||
options.AcceptAnyClientCertificate = settings.AcceptAnyClientCertificate;
|
||||
#endif
|
||||
|
||||
if (settings.CustomCertificateDefined)
|
||||
{
|
||||
options.X509StoreName = settings.CertificateSettings!.X509StoreName;
|
||||
|
||||
@@ -411,16 +411,12 @@ public partial class WireMockServer : IWireMockServer
|
||||
_dateTimeUtils
|
||||
);
|
||||
|
||||
//#if USE_ASPNETCORE
|
||||
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
|
||||
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
|
||||
_options.ClientCertificateMode = (Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode)_settings.ClientCertificateMode;
|
||||
_options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
||||
|
||||
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
|
||||
//#else
|
||||
// _httpServer = new OwinSelfHost(_options, urlOptions);
|
||||
//#endif
|
||||
var startTask = _httpServer.StartAsync();
|
||||
|
||||
using (var ctsStartTimeout = new CancellationTokenSource(settings.StartTimeout))
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.Extensions;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Settings;
|
||||
|
||||
// Based on http://blog.gauffin.org/2014/12/simple-command-line-parser/
|
||||
internal class SimpleSettingsParser
|
||||
{
|
||||
private const string Sigil = "--";
|
||||
private const string Prefix = $"{nameof(WireMockServerSettings)}__";
|
||||
private static readonly int PrefixLength = Prefix.Length;
|
||||
|
||||
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void Parse(string[] arguments, IDictionary? environment = null)
|
||||
{
|
||||
string currentName = string.Empty;
|
||||
|
||||
var values = new List<string>();
|
||||
|
||||
// Split a single argument on a space character to fix issue (e.g. Azure Service Fabric) when an argument is supplied like "--x abc" or '--x abc'
|
||||
foreach (string arg in arguments.SelectMany(arg => arg.Split(' ')))
|
||||
{
|
||||
if (arg.StartsWith(Sigil))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(currentName))
|
||||
{
|
||||
Arguments[currentName] = values.ToArray();
|
||||
}
|
||||
|
||||
values.Clear();
|
||||
currentName = arg.Substring(Sigil.Length);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(currentName))
|
||||
{
|
||||
Arguments[arg] = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currentName))
|
||||
{
|
||||
Arguments[currentName] = values.ToArray();
|
||||
}
|
||||
|
||||
// Now also parse environment
|
||||
if (environment != null)
|
||||
{
|
||||
foreach (var key in environment.Keys.OfType<string>())
|
||||
{
|
||||
if (key.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase) && environment.TryGetStringValue(key, out var value))
|
||||
{
|
||||
Arguments[key.Substring(PrefixLength)] = value.Split(' ').ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string name)
|
||||
{
|
||||
return Arguments.ContainsKey(name);
|
||||
}
|
||||
|
||||
public bool ContainsAny(params string[] names)
|
||||
{
|
||||
return names.Any(Arguments.ContainsKey);
|
||||
}
|
||||
|
||||
public string[] GetValues(string name, string[] defaultValue)
|
||||
{
|
||||
return Contains(name) ? Arguments[name] : defaultValue;
|
||||
}
|
||||
|
||||
public string[]? GetValues(string name)
|
||||
{
|
||||
return Contains(name) ? Arguments[name] : default;
|
||||
}
|
||||
|
||||
public T GetValue<T>(string name, Func<string[], T> func, T defaultValue)
|
||||
{
|
||||
return Contains(name) ? func(Arguments[name]) : defaultValue;
|
||||
}
|
||||
|
||||
public T? GetValue<T>(string name, Func<string[], T> func)
|
||||
{
|
||||
return Contains(name) ? func(Arguments[name]) : default;
|
||||
}
|
||||
|
||||
public bool GetBoolValue(string name, bool defaultValue = false)
|
||||
{
|
||||
return GetValue(name, values =>
|
||||
{
|
||||
var value = values.FirstOrDefault();
|
||||
return !string.IsNullOrEmpty(value) ? bool.Parse(value) : defaultValue;
|
||||
}, defaultValue);
|
||||
}
|
||||
|
||||
public bool GetBoolSwitchValue(string name)
|
||||
{
|
||||
return Contains(name);
|
||||
}
|
||||
|
||||
public int? GetIntValue(string name)
|
||||
{
|
||||
return GetValue<int?>(name, values =>
|
||||
{
|
||||
var value = values.FirstOrDefault();
|
||||
return !string.IsNullOrEmpty(value) ? int.Parse(value) : null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
public int GetIntValue(string name, int defaultValue)
|
||||
{
|
||||
return GetValue(name, values =>
|
||||
{
|
||||
var value = values.FirstOrDefault();
|
||||
return !string.IsNullOrEmpty(value) ? int.Parse(value) : defaultValue;
|
||||
}, defaultValue);
|
||||
}
|
||||
|
||||
public TEnum? GetEnumValue<TEnum>(string name)
|
||||
where TEnum : struct
|
||||
{
|
||||
return GetValue(name, values =>
|
||||
{
|
||||
var value = values.FirstOrDefault();
|
||||
return Enum.TryParse<TEnum>(value, true, out var enumValue) ? enumValue : (TEnum?)null;
|
||||
});
|
||||
}
|
||||
|
||||
public TEnum GetEnumValue<TEnum>(string name, TEnum defaultValue)
|
||||
where TEnum : struct
|
||||
{
|
||||
return GetValue(name, values =>
|
||||
{
|
||||
var value = values.FirstOrDefault();
|
||||
return Enum.TryParse<TEnum>(value, true, out var enumValue) ? enumValue : defaultValue;
|
||||
}, defaultValue);
|
||||
}
|
||||
|
||||
public TEnum[] GetEnumValues<TEnum>(string name, TEnum[] defaultValues)
|
||||
where TEnum : struct
|
||||
{
|
||||
var values = GetValues(name);
|
||||
if (values == null)
|
||||
{
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
var enums = new List<TEnum>();
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
if (Enum.TryParse<TEnum>(value, true, out var enumValue))
|
||||
{
|
||||
enums.Add(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
return enums.ToArray();
|
||||
}
|
||||
|
||||
public string GetStringValue(string name, string defaultValue)
|
||||
{
|
||||
return GetValue(name, values => values.FirstOrDefault() ?? defaultValue, defaultValue);
|
||||
}
|
||||
|
||||
public string? GetStringValue(string name)
|
||||
{
|
||||
return GetValue(name, values => values.FirstOrDefault());
|
||||
}
|
||||
|
||||
public T? GetObjectValueFromJson<T>(string name)
|
||||
{
|
||||
var value = GetValue(name, values => values.FirstOrDefault());
|
||||
return string.IsNullOrWhiteSpace(value) ? default : JsonUtils.DeserializeObject<T>(value);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ public static class WireMockServerSettingsParser
|
||||
ParseProxyAndRecordSettings(settings, parser);
|
||||
ParseCertificateSettings(settings, parser);
|
||||
ParseHandlebarsSettings(settings, parser);
|
||||
ParseActivityTracingSettings(settings, parser);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -226,4 +227,19 @@ public static class WireMockServerSettingsParser
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseActivityTracingSettings(WireMockServerSettings settings, SimpleSettingsParser parser)
|
||||
{
|
||||
// Only create ActivityTracingOptions if tracing is enabled
|
||||
if (parser.GetBoolValue("ActivityTracingEnabled") || parser.GetBoolValue("ActivityTracingOptions__Enabled"))
|
||||
{
|
||||
settings.ActivityTracingOptions = new ActivityTracingOptions
|
||||
{
|
||||
ExcludeAdminRequests = parser.GetBoolWithDefault("ActivityTracingExcludeAdminRequests", "ActivityTracingOptions__ExcludeAdminRequests", defaultValue: true),
|
||||
RecordRequestBody = parser.GetBoolValue("ActivityTracingRecordRequestBody") || parser.GetBoolValue("ActivityTracingOptions__RecordRequestBody"),
|
||||
RecordResponseBody = parser.GetBoolValue("ActivityTracingRecordResponseBody") || parser.GetBoolValue("ActivityTracingOptions__RecordResponseBody"),
|
||||
RecordMatchDetails = parser.GetBoolWithDefault("ActivityTracingRecordMatchDetails", "ActivityTracingOptions__RecordMatchDetails", defaultValue: true)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user