This commit is contained in:
Stef Heyenrath
2026-04-20 19:37:09 +02:00
parent 82277c7804
commit 7d1dcc6fb1
8 changed files with 45 additions and 22 deletions

View File

@@ -1,7 +1,8 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System; using JsonConverter.Abstractions;
using System.Collections.Generic; using JsonConverter.Newtonsoft.Json;
using Newtonsoft.Json;
using WireMock.Matchers.Helpers; using WireMock.Matchers.Helpers;
using WireMock.Models.Mime; using WireMock.Models.Mime;
using WireMock.Util; using WireMock.Util;
@@ -15,6 +16,8 @@ public class MimePartMatcher : IMimePartMatcher
{ {
private readonly IList<(string Name, Func<IMimePartData, MatchResult> func)> _matcherFunctions; private readonly IList<(string Name, Func<IMimePartData, MatchResult> func)> _matcherFunctions;
private readonly IJsonConverter _jsonConverter;
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(MimePartMatcher); public string Name => nameof(MimePartMatcher);
@@ -41,7 +44,8 @@ public class MimePartMatcher : IMimePartMatcher
IStringMatcher? contentTypeMatcher, IStringMatcher? contentTypeMatcher,
IStringMatcher? contentDispositionMatcher, IStringMatcher? contentDispositionMatcher,
IStringMatcher? contentTransferEncodingMatcher, IStringMatcher? contentTransferEncodingMatcher,
IMatcher? contentMatcher IMatcher? contentMatcher,
IJsonConverter? jsonConverter = null
) )
{ {
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
@@ -49,6 +53,7 @@ public class MimePartMatcher : IMimePartMatcher
ContentDispositionMatcher = contentDispositionMatcher; ContentDispositionMatcher = contentDispositionMatcher;
ContentTransferEncodingMatcher = contentTransferEncodingMatcher; ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
ContentMatcher = contentMatcher; ContentMatcher = contentMatcher;
_jsonConverter = jsonConverter ?? new NewtonsoftJsonConverter();
_matcherFunctions = []; _matcherFunctions = [];
if (ContentTypeMatcher != null) if (ContentTypeMatcher != null)
@@ -107,7 +112,8 @@ public class MimePartMatcher : IMimePartMatcher
ContentType = GetContentTypeAsString(mimePart.ContentType), ContentType = GetContentTypeAsString(mimePart.ContentType),
DeserializeJson = true, DeserializeJson = true,
ContentEncoding = null, // mimePart.ContentType?.CharsetEncoding.ToString(), ContentEncoding = null, // mimePart.ContentType?.CharsetEncoding.ToString(),
DecompressGZipAndDeflate = true DecompressGZipAndDeflate = true,
DefaultJsonConverter = _jsonConverter
}; };
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult(); var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();

View File

@@ -1,8 +1,7 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using JsonConverter.Abstractions;
using WireMock.Util; using WireMock.Util;
namespace WireMock.Http; namespace WireMock.Http;
@@ -15,7 +14,8 @@ internal static class HttpResponseMessageHelper
Uri originalUri, Uri originalUri,
bool deserializeJson, bool deserializeJson,
bool decompressGzipAndDeflate, bool decompressGzipAndDeflate,
bool deserializeFormUrlEncoded) bool deserializeFormUrlEncoded,
IJsonConverter jsonConverter)
{ {
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode }; var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
@@ -45,7 +45,8 @@ internal static class HttpResponseMessageHelper
DeserializeJson = deserializeJson, DeserializeJson = deserializeJson,
ContentEncoding = contentEncodingHeader?.FirstOrDefault(), ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
DecompressGZipAndDeflate = decompressGzipAndDeflate, DecompressGZipAndDeflate = decompressGzipAndDeflate,
DeserializeFormUrlEncoded = deserializeFormUrlEncoded DeserializeFormUrlEncoded = deserializeFormUrlEncoded,
DefaultJsonConverter = jsonConverter
}; };
responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false); responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
} }

View File

@@ -1,6 +1,5 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Matchers.Helpers; using WireMock.Matchers.Helpers;
using WireMock.Util; using WireMock.Util;

View File

@@ -53,7 +53,8 @@ internal class OwinRequestMapper : IOwinRequestMapper
ContentType = request.ContentType, ContentType = request.ContentType,
DeserializeJson = !options.DisableJsonBodyParsing.GetValueOrDefault(false), DeserializeJson = !options.DisableJsonBodyParsing.GetValueOrDefault(false),
ContentEncoding = contentEncodingHeader?.FirstOrDefault(), ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
DecompressGZipAndDeflate = !options.DisableRequestBodyDecompressing.GetValueOrDefault(false) DecompressGZipAndDeflate = !options.DisableRequestBodyDecompressing.GetValueOrDefault(false),
DefaultJsonConverter = options.DefaultJsonSerializer
}; };
body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false); body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);

View File

@@ -48,7 +48,8 @@ internal class ProxyHelper(WireMockServerSettings settings)
originalUri, originalUri,
deserializeJson, deserializeJson,
decompressGzipAndDeflate, decompressGzipAndDeflate,
deserializeFormUrlEncoded deserializeFormUrlEncoded,
_settings.DefaultJsonSerializer
).ConfigureAwait(false); ).ConfigureAwait(false);
IMapping? newMapping = null; IMapping? newMapping = null;

View File

@@ -128,11 +128,11 @@ internal static class BodyParser
{ {
Guard.NotNull(settings); Guard.NotNull(settings);
var bodyWithContentEncoding = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false); var (ContentType, Bytes) = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false);
var data = new BodyData var data = new BodyData
{ {
BodyAsBytes = bodyWithContentEncoding.Bytes, BodyAsBytes = Bytes,
DetectedCompression = bodyWithContentEncoding.ContentType, DetectedCompression = ContentType,
DetectedBodyType = BodyType.Bytes, DetectedBodyType = BodyType.Bytes,
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType) DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType)
}; };
@@ -168,17 +168,17 @@ internal static class BodyParser
data.DetectedBodyType = BodyType.FormUrlEncoded; data.DetectedBodyType = BodyType.FormUrlEncoded;
} }
// If string is not null or empty, try to deserialize the string to a JObject // If string is not null or empty, try to deserialize the string
if (settings.DeserializeJson && JsonUtils.IsJson(data.BodyAsString)) if (settings.DeserializeJson && settings.DefaultJsonConverter.IsValidJson(data.BodyAsString))
{ {
try try
{ {
data.BodyAsJson = JsonUtils.DeserializeObject(data.BodyAsString); data.BodyAsJson = settings.DefaultJsonConverter.Deserialize<object>(data.BodyAsString);
data.DetectedBodyType = BodyType.Json; data.DetectedBodyType = BodyType.Json;
} }
catch catch
{ {
// JsonConvert failed, just ignore. // JsonConverter failed, just ignore.
} }
} }
} }
@@ -201,7 +201,7 @@ internal static class BodyParser
return (null, data); return (null, data);
} }
public static bool IsProbablyText(byte[] data) private static bool IsProbablyText(byte[] data)
{ {
if (data.Length == 0) if (data.Length == 0)
{ {

View File

@@ -1,6 +1,7 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System.IO; using JsonConverter.Abstractions;
using JsonConverter.Newtonsoft.Json;
namespace WireMock.Util; namespace WireMock.Util;
@@ -35,4 +36,13 @@ internal class BodyParserSettings
/// Try to deserialize the body as FormUrlEncoded. /// Try to deserialize the body as FormUrlEncoded.
/// </summary> /// </summary>
public bool DeserializeFormUrlEncoded { get; set; } = true; public bool DeserializeFormUrlEncoded { get; set; } = true;
/// <summary>
/// Gets or sets the default JSON converter used for deserialization.
/// </summary>
/// <remarks>
/// Set this property to customize how objects are serialized to and deserialized from JSON during mapping.
/// Default is <see cref="NewtonsoftJsonConverter"/>.
/// </remarks>
public IJsonConverter DefaultJsonConverter { get; set; } = new NewtonsoftJsonConverter();
} }

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using JsonConverter.System.Text.Json; using JsonConverter.System.Text.Json;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Net.Xunit;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
@@ -232,9 +233,13 @@ public partial class WireMockServerTests
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_JsonPartialWildcardMatcher_And_SystemTextJson_ShouldMatch() public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_JsonPartialWildcardMatcher_And_SystemTextJson_ShouldMatch()
{ {
// Arrange // Arrange
using var server = WireMockServer.Start(x => x.DefaultJsonSerializer = new SystemTextJsonConverter()); using var server = WireMockServer.Start(settings =>
{
settings.Logger = new TestOutputHelperWireMockLogger(testOutputHelper);
settings.DefaultJsonSerializer = new SystemTextJsonConverter();
});
var matcher = new JsonPartialWildcardMatcher(new { id = "^[a-f0-9]{32}-[0-9]$" }, ignoreCase: true, regex: true); var matcher = new SystemTextJsonPartialWildcardMatcher(new { id = "^[a-f0-9]{32}-[0-9]$" }, ignoreCase: true, regex: true);
server.Given(Request.Create() server.Given(Request.Create()
.WithHeader("Content-Type", "application/json*") .WithHeader("Content-Type", "application/json*")
.UsingPost() .UsingPost()