From 708af550515bebe17f3760533fd3cf5465dbe96d Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 20 Dec 2025 10:32:26 +0100 Subject: [PATCH] 0.8.0 --- .../Admin/Mappings/ResponseModel.cs | 2 +- .../Models/IBodyData.cs | 2 +- .../WireMock.Net.Extensions.Routing.csproj | 4 +-- src/WireMock.Net.Minimal/MappingBuilder.cs | 5 ++- .../Serialization/MappingToFileSaver.cs | 10 ++++-- .../Server/WireMockServer.Admin.cs | 20 +++++++----- .../Server/WireMockServer.cs | 3 +- .../WireMock.Net.Minimal.csproj | 10 +++--- .../WireMock.Net.RestClient.csproj | 2 +- .../JsonSerializationConstants.cs | 19 ++++++++---- .../Settings/WireMockServerSettings.cs | 7 +++-- .../WireMock.Net.Shared.csproj | 7 +++-- .../ResponseBuilders/ResponseWithBodyTests.cs | 31 ++++++++++++++++--- .../WireMock.Net.Tests.csproj | 4 +-- 14 files changed, 83 insertions(+), 43 deletions(-) diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs index 3570439e..7f585c32 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs @@ -32,7 +32,7 @@ public class ResponseModel public object? BodyAsJson { get; set; } /// - /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. + /// Gets or sets a value indicating whether the Json Body String needs to be indented. /// public bool? BodyAsJsonIndented { get; set; } diff --git a/src/WireMock.Net.Abstractions/Models/IBodyData.cs b/src/WireMock.Net.Abstractions/Models/IBodyData.cs index 79b737d5..593d4c40 100644 --- a/src/WireMock.Net.Abstractions/Models/IBodyData.cs +++ b/src/WireMock.Net.Abstractions/Models/IBodyData.cs @@ -37,7 +37,7 @@ public interface IBodyData object? BodyAsJson { get; set; } /// - /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. + /// Gets or sets a value indicating whether the Json Body String needs to be indented. /// bool? BodyAsJsonIndented { get; set; } diff --git a/src/WireMock.Net.Extensions.Routing/WireMock.Net.Extensions.Routing.csproj b/src/WireMock.Net.Extensions.Routing/WireMock.Net.Extensions.Routing.csproj index 70791227..533c93a7 100644 --- a/src/WireMock.Net.Extensions.Routing/WireMock.Net.Extensions.Routing.csproj +++ b/src/WireMock.Net.Extensions.Routing/WireMock.Net.Extensions.Routing.csproj @@ -1,4 +1,4 @@ - + WireMock.Net.Routing extends WireMock.Net with modern, minimal-API-style routing for .NET Gennadii Saltyshchak @@ -25,7 +25,7 @@ - + diff --git a/src/WireMock.Net.Minimal/MappingBuilder.cs b/src/WireMock.Net.Minimal/MappingBuilder.cs index 6e900e1a..79b85ef6 100644 --- a/src/WireMock.Net.Minimal/MappingBuilder.cs +++ b/src/WireMock.Net.Minimal/MappingBuilder.cs @@ -3,7 +3,6 @@ using System; using System.Linq; using System.Text; -using Newtonsoft.Json; using Stef.Validation; using WireMock.Admin.Mappings; using WireMock.Matchers.Request; @@ -164,8 +163,8 @@ public class MappingBuilder : IMappingBuilder } } - private static string ToJson(object value) + private string ToJson(object value) { - return JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsDefault); + return _settings.DefaultJsonSerializer.Serialize(value, JsonSerializationConstants.JsonConverterOptionsDefault); } } \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/Serialization/MappingToFileSaver.cs b/src/WireMock.Net.Minimal/Serialization/MappingToFileSaver.cs index 3e6c8610..cd76888b 100644 --- a/src/WireMock.Net.Minimal/Serialization/MappingToFileSaver.cs +++ b/src/WireMock.Net.Minimal/Serialization/MappingToFileSaver.cs @@ -2,7 +2,8 @@ using System.IO; using System.Linq; -using Newtonsoft.Json; +using JsonConverter.Abstractions; +using JsonConverter.Newtonsoft.Json; using Stef.Validation; using WireMock.Settings; @@ -12,12 +13,15 @@ internal class MappingToFileSaver { private readonly WireMockServerSettings _settings; private readonly MappingConverter _mappingConverter; + private readonly IJsonConverter _jsonConverter; private readonly MappingFileNameSanitizer _fileNameSanitizer; public MappingToFileSaver(WireMockServerSettings settings, MappingConverter mappingConverter) { _settings = Guard.NotNull(settings); _mappingConverter = Guard.NotNull(mappingConverter); + + _jsonConverter = settings.DefaultJsonSerializer ?? new NewtonsoftJsonConverter(); _fileNameSanitizer = new MappingFileNameSanitizer(settings); } @@ -56,6 +60,8 @@ internal class MappingToFileSaver { _settings.Logger.Info("Saving Mapping file {0}", path); - _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsDefault)); + var json = _jsonConverter.Serialize(value, JsonSerializationConstants.JsonConverterOptionsDefault); + + _settings.FileSystemHandler.WriteMappingFile(path, json); } } \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs index 96ce9ad1..45dbc141 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.Admin.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Net; using System.Text; using JetBrains.Annotations; -using Newtonsoft.Json; +using JsonConverter.Abstractions; using Newtonsoft.Json.Linq; using Stef.Validation; using WireMock.Admin.Mappings; @@ -826,25 +826,31 @@ public partial class WireMockServer } } - private static Encoding? ToEncoding(EncodingModel? encodingModel) + private ResponseMessage ToJson(T result, bool keepNullValues = false, object? statusCode = null) { - return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null; - } + var jsonOptions = new JsonConverterOptions + { + WriteIndented = true, + IgnoreNullValues = !keepNullValues + }; - private static ResponseMessage ToJson(T result, bool keepNullValues = false, object? statusCode = null) - { return new ResponseMessage { BodyData = new BodyData { DetectedBodyType = BodyType.String, - BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues : JsonSerializationConstants.JsonSerializerSettingsDefault) + BodyAsString = _settings.DefaultJsonSerializer.Serialize(result!, jsonOptions) }, StatusCode = statusCode ?? (int)HttpStatusCode.OK, Headers = new Dictionary> { { HttpKnownHeaderNames.ContentType, new WireMockList(WireMockConstants.ContentTypeJson) } } }; } + private static Encoding? ToEncoding(EncodingModel? encodingModel) + { + return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null; + } + private static ResponseMessage ToResponseMessage(string text) { return new ResponseMessage diff --git a/src/WireMock.Net.Minimal/Server/WireMockServer.cs b/src/WireMock.Net.Minimal/Server/WireMockServer.cs index 71a8efb7..99a1df30 100644 --- a/src/WireMock.Net.Minimal/Server/WireMockServer.cs +++ b/src/WireMock.Net.Minimal/Server/WireMockServer.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; -using System.Runtime; using System.Threading; using AnyOfTypes; using JetBrains.Annotations; @@ -360,7 +359,7 @@ public partial class WireMockServer : IWireMockServer { _settings = Guard.NotNull(settings); - _mappingSerializer = new MappingSerializer(settings.MappingJsonSerializer ?? new NewtonsoftJsonConverter()); + _mappingSerializer = new MappingSerializer(settings.DefaultJsonSerializer ?? new NewtonsoftJsonConverter()); // Set default values if not provided _settings.Logger = settings.Logger ?? new WireMockNullLogger(); diff --git a/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj b/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj index 57b60323..f7c3d2da 100644 --- a/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj +++ b/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj @@ -1,4 +1,4 @@ - + Minimal version from the lightweight Http Mocking Server for .NET WireMock.Net.Minimal @@ -57,8 +57,8 @@ - - + + @@ -118,13 +118,13 @@ - + - + diff --git a/src/WireMock.Net.RestClient/WireMock.Net.RestClient.csproj b/src/WireMock.Net.RestClient/WireMock.Net.RestClient.csproj index 3baecc43..bff6b9b6 100644 --- a/src/WireMock.Net.RestClient/WireMock.Net.RestClient.csproj +++ b/src/WireMock.Net.RestClient/WireMock.Net.RestClient.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/WireMock.Net.Shared/Serialization/JsonSerializationConstants.cs b/src/WireMock.Net.Shared/Serialization/JsonSerializationConstants.cs index 1fd258a5..f1b31ef3 100644 --- a/src/WireMock.Net.Shared/Serialization/JsonSerializationConstants.cs +++ b/src/WireMock.Net.Shared/Serialization/JsonSerializationConstants.cs @@ -1,5 +1,6 @@ // Copyright © WireMock.Net +using JsonConverter.Abstractions; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -7,24 +8,30 @@ namespace WireMock.Serialization; internal static class JsonSerializationConstants { - public static readonly JsonSerializerSettings JsonSerializerSettingsDefault = new() + internal static readonly JsonConverterOptions JsonConverterOptionsDefault = new() { - Formatting = Formatting.Indented, - NullValueHandling = NullValueHandling.Ignore + WriteIndented = true, + IgnoreNullValues = true }; - public static readonly JsonSerializerSettings JsonSerializerSettingsIncludeNullValues = new() + //internal static readonly JsonSerializerSettings JsonSerializerSettingsDefault = new() + //{ + // Formatting = Formatting.Indented, + // NullValueHandling = NullValueHandling.Ignore + //}; + + internal static readonly JsonSerializerSettings JsonSerializerSettingsIncludeNullValues = new() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Include }; - public static readonly JsonSerializerSettings JsonDeserializerSettingsWithDateParsingNone = new() + internal static readonly JsonSerializerSettings JsonDeserializerSettingsWithDateParsingNone = new() { DateParseHandling = DateParseHandling.None }; - public static readonly JsonSerializerSettings JsonSerializerSettingsPact = new() + internal static readonly JsonSerializerSettings JsonSerializerSettingsPact = new() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, diff --git a/src/WireMock.Net.Shared/Settings/WireMockServerSettings.cs b/src/WireMock.Net.Shared/Settings/WireMockServerSettings.cs index bf1cbd8a..8e63fd9b 100644 --- a/src/WireMock.Net.Shared/Settings/WireMockServerSettings.cs +++ b/src/WireMock.Net.Shared/Settings/WireMockServerSettings.cs @@ -15,6 +15,7 @@ using WireMock.Types; using System.Globalization; using WireMock.Models; using JsonConverter.Abstractions; +using JsonConverter.Newtonsoft.Json; #if USE_ASPNETCORE using Microsoft.Extensions.DependencyInjection; @@ -341,12 +342,12 @@ public class WireMockServerSettings public HandlebarsSettings? HandlebarsSettings { get; set; } /// - /// Gets or sets the JSON converter used for MappingModel serialization. + /// Gets or sets the default JSON converter used for serialization. /// /// /// Set this property to customize how objects are serialized to and deserialized from JSON during mapping. - /// If not set, the NewtonsoftJsonConverter will be used. + /// Default is . /// [PublicAPI] - public IJsonConverter? MappingJsonSerializer { get; set; } + public IJsonConverter DefaultJsonSerializer { get; set; } = new NewtonsoftJsonConverter(); } \ No newline at end of file diff --git a/src/WireMock.Net.Shared/WireMock.Net.Shared.csproj b/src/WireMock.Net.Shared/WireMock.Net.Shared.csproj index 2b01dd01..ced033fb 100644 --- a/src/WireMock.Net.Shared/WireMock.Net.Shared.csproj +++ b/src/WireMock.Net.Shared/WireMock.Net.Shared.csproj @@ -1,4 +1,4 @@ - + Shared interfaces, models, enumerations and types. Stef Heyenrath @@ -48,9 +48,10 @@ - + - + + diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs index 253d1ab8..151de0f7 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs @@ -4,6 +4,7 @@ using System; using System.Text; using System.Threading.Tasks; using FluentAssertions; +using JsonConverter.Newtonsoft.Json; using Moq; using Newtonsoft.Json.Linq; using NFluent; @@ -316,12 +317,11 @@ public class ResponseWithBodyTests var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request1, _settings).ConfigureAwait(false); Check.That(response.Message.StatusCode).IsEqualTo(200); - Check.That(response.Message.BodyData.BodyAsString).Contains("File deleted."); + Check.That(response.Message.BodyData?.BodyAsString).Contains("File deleted."); } -#if !(NET451 || NET452) [Fact] - public async Task Response_ProvideResponse_WithBody_IJsonConverter_SystemTextJson() + public async Task Response_ProvideResponse_WithBody_NewtonsoftJsonConverter() { // Arrange var requestBody = new BodyData @@ -331,13 +331,34 @@ public class ResponseWithBodyTests }; var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, requestBody); - var responseBuilder = Response.Create().WithBody(new { foo = "bar", n = 42 }, new JsonConverter.System.Text.Json.SystemTextJsonConverter()); + var responseBuilder = Response.Create().WithBody(new { foo = "< > & ' 😀 👍 ❤️", n = 42 }, new NewtonsoftJsonConverter()); // Act var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false); // Assert - response.Message.BodyData!.BodyAsString.Should().Be(@"{""foo"":""bar"",""n"":42}"); + response.Message.BodyData!.BodyAsString.Should().Be("""{"foo":"< > & ' 😀 👍 ❤️","n":42}"""); + } + +#if !(NET451 || NET452 || NET461) + [Fact] + public async Task Response_ProvideResponse_WithBody_SystemTextJsonConverter() + { + // Arrange + var requestBody = new BodyData + { + DetectedBodyType = BodyType.String, + BodyAsString = "abc" + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, requestBody); + + var responseBuilder = Response.Create().WithBody(new { foo = "< > & ' 😀 👍 ❤️", n = 42 }, new JsonConverter.System.Text.Json.SystemTextJsonConverter()); + + // Act + var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false); + + // Assert + response.Message.BodyData!.BodyAsString.Should().Be("""{"foo":"\u003C \u003E \u0026 \u0027 \uD83D\uDE00 \uD83D\uDC4D \u2764\uFE0F","n":42}"""); } #endif } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index 3602674f..f1720cef 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -1,4 +1,4 @@ - + Stef Heyenrath @@ -103,7 +103,7 @@ - +