diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd5b095e..3ad45b0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,432 +1,212 @@
+# 1.7.5-preview-02 (03 April 2025)
+- [#1265](https://github.com/WireMock-Net/WireMock.Net/pull/1265) - Fix construction of path in OpenApiParser [bug] contributed by [StefH](https://github.com/StefH)
+- [#1269](https://github.com/WireMock-Net/WireMock.Net/pull/1269) - Server-Sent Events [feature] contributed by [StefH](https://github.com/StefH)
+- [#1264](https://github.com/WireMock-Net/WireMock.Net/issues/1264) - OpenApiParser - Construction of path possibly incorrect [bug]
+
# 1.7.4 (27 February 2025)
-- [#1256](https://github.com/WireMock-Net/WireMock.Net/pull/1256) - Add ToArray() to ConcurrentObservableCollection [bug] contributed by [StefH](https://github.com/StefH)
- [#1254](https://github.com/WireMock-Net/WireMock.Net/issues/1254) - FindLogEntries exception 'Destination array was not long enough' [bug]
# 1.7.3 (24 February 2025)
-- [#1253](https://github.com/WireMock-Net/WireMock.Net/pull/1253) - Update QueryStringParser to support param with equal but no value [bug] contributed by [StefH](https://github.com/StefH)
- [#1247](https://github.com/WireMock-Net/WireMock.Net/issues/1247) - API call isn't matched when using an empty query string parameter [bug]
# 1.7.2 (12 February 2025)
-- [#1246](https://github.com/WireMock-Net/WireMock.Net/pull/1246) - Add "AddUrl" to WireMockContainerBuilder to support grpc [feature] contributed by [StefH](https://github.com/StefH)
-- [#1248](https://github.com/WireMock-Net/WireMock.Net/pull/1248) - Add exception message to logging when mapping fails due to an exception. contributed by [JvE-iO](https://github.com/JvE-iO)
-- [#1250](https://github.com/WireMock-Net/WireMock.Net/pull/1250) - Add ProtoDefinition to WireMockContainer [feature] contributed by [StefH](https://github.com/StefH)
- [#1239](https://github.com/WireMock-Net/WireMock.Net/issues/1239) - How to use WiremockContainerBuilder for grpc using http2 [feature]
- [#1249](https://github.com/WireMock-Net/WireMock.Net/issues/1249) - Add protodefinition and refer it from mapping [feature]
# 1.7.1 (26 January 2025)
-- [#1236](https://github.com/WireMock-Net/WireMock.Net/pull/1236) - Fix ProtoBuf mapping.json [bug] contributed by [StefH](https://github.com/StefH)
-- [#1245](https://github.com/WireMock-Net/WireMock.Net/pull/1245) - Use Handlebars.Net.Helpers to version 2.4.10 [feature] contributed by [StefH](https://github.com/StefH)
- [#1233](https://github.com/WireMock-Net/WireMock.Net/issues/1233) - GRPC mappings are not created correctly when created through Admin API [bug]
-# 1.7.0 (22 January 2025)
-- [#1242](https://github.com/WireMock-Net/WireMock.Net/pull/1242) - Disable DynamicLinq to fix CVE [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.6.12 (21 January 2025)
-- [#1231](https://github.com/WireMock-Net/WireMock.Net/pull/1231) - Fix google protobuf WellKnownTypes: Empty, Duration and Timestamp [bug] contributed by [StefH](https://github.com/StefH)
-- [#1235](https://github.com/WireMock-Net/WireMock.Net/pull/1235) - Fix ArgumentException in FindLogEntries [bug] contributed by [StefH](https://github.com/StefH)
-- [#1241](https://github.com/WireMock-Net/WireMock.Net/pull/1241) - Upgrade to Handlebars.Net.Helpers 2.4.9 [bug] contributed by [StefH](https://github.com/StefH)
- [#1227](https://github.com/WireMock-Net/WireMock.Net/issues/1227) - unable to call grpc method with namespace [bug]
- [#1228](https://github.com/WireMock-Net/WireMock.Net/issues/1228) - how to set datetime for grpc field [bug]
- [#1234](https://github.com/WireMock-Net/WireMock.Net/issues/1234) - FindLogEntries regression [bug]
- [#1240](https://github.com/WireMock-Net/WireMock.Net/issues/1240) - Method 'get_Category' in type 'WireMock.Transformers.Handlebars.FileHelpers' [bug]
# 1.6.11 (02 January 2025)
-- [#1221](https://github.com/WireMock-Net/WireMock.Net/pull/1221) - Add overloads to AtUrl and AtAbsoluteUrl which can use a IStringMatcher [feature] contributed by [StefH](https://github.com/StefH)
-- [#1222](https://github.com/WireMock-Net/WireMock.Net/pull/1222) - Fix WireMockContainerBuilder (duplicate entries) [bug] contributed by [StefH](https://github.com/StefH)
-- [#1223](https://github.com/WireMock-Net/WireMock.Net/pull/1223) - Add functionality to call a PostTransform method after the Webhook request has been transformed [feature] contributed by [StefH](https://github.com/StefH)
-- [#1224](https://github.com/WireMock-Net/WireMock.Net/pull/1224) - Add FindLogEntries to IWireMockServer [feature] contributed by [StefH](https://github.com/StefH)
- [#1092](https://github.com/WireMock-Net/WireMock.Net/issues/1092) - FindLogEntries present in WireMockServer but not IWireMockServer [feature]
- [#1192](https://github.com/WireMock-Net/WireMock.Net/issues/1192) - Feature: add URL assertion excluding query parameters [feature]
- [#1204](https://github.com/WireMock-Net/WireMock.Net/issues/1204) - Supplying Values From Request for Webhook Body and Headers [feature]
- [#1217](https://github.com/WireMock-Net/WireMock.Net/issues/1217) - Order of WireMockContainerBuilder WithX calls caused duplicate Networks in Configuration [bug]
# 1.6.10 (15 December 2024)
-- [#1189](https://github.com/WireMock-Net/WireMock.Net/pull/1189) - WireMock.Net.Testcontainers: implement watching the static mapping folder for changes [bug] contributed by [StefH](https://github.com/StefH)
- [#1188](https://github.com/WireMock-Net/WireMock.Net/issues/1188) - WithWatchStaticMappings doesn't respect new files [bug]
# 1.6.9 (06 December 2024)
-- [#1216](https://github.com/WireMock-Net/WireMock.Net/pull/1216) - Fix JsonPartialMatcher when using property names with dot [bug] contributed by [StefH](https://github.com/StefH)
- [#1210](https://github.com/WireMock-Net/WireMock.Net/issues/1210) - JsonPartialMatcher fails to match on property name that JsonMatcher matches [bug]
# 1.6.8 (24 November 2024)
-- [#1202](https://github.com/WireMock-Net/WireMock.Net/pull/1202) - Log exception when (static) mapping file cannot be read [feature] contributed by [StefH](https://github.com/StefH)
-- [#1206](https://github.com/WireMock-Net/WireMock.Net/pull/1206) - Fix security issues [bug] contributed by [StefH](https://github.com/StefH)
-- [#1211](https://github.com/WireMock-Net/WireMock.Net/pull/1211) - Use GraphQL 8.2.1 [feature] contributed by [StefH](https://github.com/StefH)
-- [#1213](https://github.com/WireMock-Net/WireMock.Net/pull/1213) - Fix HandlebarsContext ParseAndEvaluate method [bug] contributed by [StefH](https://github.com/StefH)
- [#1201](https://github.com/WireMock-Net/WireMock.Net/issues/1201) - Mapping file parse errors are not logged to the console [feature]
- [#1209](https://github.com/WireMock-Net/WireMock.Net/issues/1209) - Upgrade of GraphQL libs to the latest [feature]
- [#1212](https://github.com/WireMock-Net/WireMock.Net/issues/1212) - Response Body Does Not Include Text After Path Segment [bug]
# 1.6.7 (17 October 2024)
-- [#1161](https://github.com/WireMock-Net/WireMock.Net/pull/1161) - Use latest ProtoBufJsonConverter to support WellKnownTypes [bug] contributed by [StefH](https://github.com/StefH)
-- [#1190](https://github.com/WireMock-Net/WireMock.Net/pull/1190) - Bump System.Text.Json from 8.0.4 to 8.0.5 in /examples/WireMock.Net.Console.Net472.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#1194](https://github.com/WireMock-Net/WireMock.Net/pull/1194) - Upgrade System.Text.RegularExpressions to 4.3.1 to solve CVE-2019-0820 [bug] contributed by [StefH](https://github.com/StefH)
-- [#1197](https://github.com/WireMock-Net/WireMock.Net/pull/1197) - Bump System.Text.Json from 8.0.4 to 8.0.5 in /src/dotnet-WireMock.Net [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#1198](https://github.com/WireMock-Net/WireMock.Net/pull/1198) - Fix Google.Protobuf.WellKnownTypes.Value [bug] contributed by [StefH](https://github.com/StefH)
- [#1144](https://github.com/WireMock-Net/WireMock.Net/issues/1144) - Using google.protobuf.Empty as response results in a bad gRPC response [bug]
- [#1153](https://github.com/WireMock-Net/WireMock.Net/issues/1153) - Grpc support for multiple proto files [feature]
- [#1193](https://github.com/WireMock-Net/WireMock.Net/issues/1193) - Snyk issue : Regular Expression Denial of Service [bug]
# 1.6.6 (01 October 2024)
-- [#1185](https://github.com/WireMock-Net/WireMock.Net/pull/1185) - Throw exception in case WithTransformer is used after WithBodyFromFile [bug] contributed by [StefH](https://github.com/StefH)
-- [#1187](https://github.com/WireMock-Net/WireMock.Net/pull/1187) - Fix StaticMappingsPath in WireMockContainerBuilder [bug] contributed by [StefH](https://github.com/StefH)
- [#1184](https://github.com/WireMock-Net/WireMock.Net/issues/1184) - .WithBodyFromFile() + .WithTransformer(transformContentFromBodyAsFile: true) = empty string [bug]
- [#1186](https://github.com/WireMock-Net/WireMock.Net/issues/1186) - WithMappings path is null on Build() call [bug]
-# 1.6.5 (28 September 2024)
-- [#1175](https://github.com/WireMock-Net/WireMock.Net/pull/1175) - Add WireMock.Net.AspNetCore.Middleware [feature] contributed by [StefH](https://github.com/StefH)
-- [#1181](https://github.com/WireMock-Net/WireMock.Net/pull/1181) - WireMock.Net.Testcontainers: Use 'sheyenrath/wiremock.net-alpine' image as default for Linux [feature] contributed by [StefH](https://github.com/StefH)
-- [#1182](https://github.com/WireMock-Net/WireMock.Net/pull/1182) - pass in the request when no matching is found to the warn logger [feature] contributed by [JasonLandbridge](https://github.com/JasonLandbridge)
-
# 1.6.4 (25 September 2024)
-- [#1169](https://github.com/WireMock-Net/WireMock.Net/pull/1169) - Allow mapping without Path or Url [bug] contributed by [StefH](https://github.com/StefH)
-- [#1170](https://github.com/WireMock-Net/WireMock.Net/pull/1170) - Update the .NET Aspire tests [feature] contributed by [StefH](https://github.com/StefH)
-- [#1172](https://github.com/WireMock-Net/WireMock.Net/pull/1172) - Fix JSON parsing of text/plain content type [bug] contributed by [ruxo](https://github.com/ruxo)
-- [#1177](https://github.com/WireMock-Net/WireMock.Net/pull/1177) - Unpin Testcontainers version and upgrade to version 3.10.0 [bug] contributed by [StefH](https://github.com/StefH)
-- [#1178](https://github.com/WireMock-Net/WireMock.Net/pull/1178) - Upgrade CS-Script to version 4.8.17 [feature] contributed by [StefH](https://github.com/StefH)
-- [#1179](https://github.com/WireMock-Net/WireMock.Net/pull/1179) - Add WireMock.Net.TUnit project [feature] contributed by [StefH](https://github.com/StefH)
- [#1146](https://github.com/WireMock-Net/WireMock.Net/issues/1146) - Bump Request CS-Script 4.8.13 to 4.8.17 [feature]
- [#1167](https://github.com/WireMock-Net/WireMock.Net/issues/1167) - Admin API fails to create a mapping with Request Header matching using WildCardMatcher [bug]
- [#1168](https://github.com/WireMock-Net/WireMock.Net/issues/1168) - Numbers in text/plain content is parsed as JSON. [bug]
- [#1176](https://github.com/WireMock-Net/WireMock.Net/issues/1176) - WireMock.NET TestContainer Dependency Constraint Issue [bug]
# 1.6.3 (07 September 2024)
-- [#1165](https://github.com/WireMock-Net/WireMock.Net/pull/1165) - Fix listen on AnyIP for url 0.0.0.0 contributed by [cocoon](https://github.com/cocoon)
- [#1154](https://github.com/WireMock-Net/WireMock.Net/issues/1154) - Listen on all ips [bug]
# 1.6.2 (04 September 2024)
-- [#1152](https://github.com/WireMock-Net/WireMock.Net/pull/1152) - Update MappingConverter to correctly write the Matcher as C# code [bug] contributed by [StefH](https://github.com/StefH)
-- [#1163](https://github.com/WireMock-Net/WireMock.Net/pull/1163) - Upgrade Aspire to version 8.2.0 [feature] contributed by [StefH](https://github.com/StefH)
-- [#1166](https://github.com/WireMock-Net/WireMock.Net/pull/1166) - Also update IWireMockMiddlewareOptions when settings are updated via admin interface [bug] contributed by [StefH](https://github.com/StefH)
- [#1151](https://github.com/WireMock-Net/WireMock.Net/issues/1151) - MappingsToCSharpCode should use RegexMatcher when specified [bug]
- [#1164](https://github.com/WireMock-Net/WireMock.Net/issues/1164) - WithParam not working. [bug]
# 1.6.1 (22 August 2024)
-- [#1160](https://github.com/WireMock-Net/WireMock.Net/pull/1160) - Use default timeout for Regex [bug] contributed by [StefH](https://github.com/StefH)
- [#1159](https://github.com/WireMock-Net/WireMock.Net/issues/1159) - RegexMatchTimeoutException when trying to parse HTTP version [bug]
# 1.6.0 (16 August 2024)
-- [#1042](https://github.com/WireMock-Net/WireMock.Net/pull/1042) - Update + add fluent builder methods [feature] contributed by [StefH](https://github.com/StefH)
-- [#1109](https://github.com/WireMock-Net/WireMock.Net/pull/1109) - Add Aspire Extension [feature] contributed by [StefH](https://github.com/StefH)
-- [#1148](https://github.com/WireMock-Net/WireMock.Net/pull/1148) - Use Guid.TryParseExact with format "D" contributed by [StefH](https://github.com/StefH)
-- [#1157](https://github.com/WireMock-Net/WireMock.Net/pull/1157) - Fix FormUrlEncodedMatcher (MatchOperator.And) [bug] contributed by [StefH](https://github.com/StefH)
-- [#1158](https://github.com/WireMock-Net/WireMock.Net/pull/1158) - Allow setting Content-Length header on the response [feature] contributed by [StefH](https://github.com/StefH)
- [#720](https://github.com/WireMock-Net/WireMock.Net/issues/720) - Response Header Content-Length not available when call HEAD Method [feature]
- [#1145](https://github.com/WireMock-Net/WireMock.Net/issues/1145) - Response is auto converting string to guid [bug]
- [#1156](https://github.com/WireMock-Net/WireMock.Net/issues/1156) - FormUrlEncodedMatcher is not requiring to match all properties when MatchOperator.And [bug]
# 1.5.62 (27 July 2024)
-- [#1147](https://github.com/WireMock-Net/WireMock.Net/pull/1147) - Add FormUrlEncodedMatcher [feature] contributed by [StefH](https://github.com/StefH)
- [#1143](https://github.com/WireMock-Net/WireMock.Net/issues/1143) - FormEncoded Request fails (404 Not Found) if key value pairs order in mapping is different from request body order [bug]
# 1.5.61 (22 July 2024)
-- [#1122](https://github.com/WireMock-Net/WireMock.Net/pull/1122) - Fix OpenApiPathsMapper [bug] contributed by [StefH](https://github.com/StefH)
-- [#1135](https://github.com/WireMock-Net/WireMock.Net/pull/1135) - Bump System.Text.Json from 4.7.2 to 8.0.4 in /examples/WireMock.Net.Console.Net472.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#1136](https://github.com/WireMock-Net/WireMock.Net/pull/1136) - Bump System.Text.Json from 8.0.0 to 8.0.4 in /src/dotnet-WireMock.Net [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#1137](https://github.com/WireMock-Net/WireMock.Net/pull/1137) - Add link to TIOBE Index on main page + fix issues [refactor] contributed by [StefH](https://github.com/StefH)
-- [#1138](https://github.com/WireMock-Net/WireMock.Net/pull/1138) - Fix some SonarCloud warnings [refactor] contributed by [StefH](https://github.com/StefH)
-- [#1141](https://github.com/WireMock-Net/WireMock.Net/pull/1141) - Update WireMockContainerBuilder.WithMappings for "includeSubDirectories" [feature] contributed by [StefH](https://github.com/StefH)
-- [#1142](https://github.com/WireMock-Net/WireMock.Net/pull/1142) - Make property FromConfiguredStub nullable (for WireMock.Org) [bug] contributed by [StefH](https://github.com/StefH)
- [#1118](https://github.com/WireMock-Net/WireMock.Net/issues/1118) - Generating mappings from Payroc open-api file gives ArgumentException: Property with the same name already exists on object [bug]
- [#1139](https://github.com/WireMock-Net/WireMock.Net/issues/1139) - Allow WithMappings to support scanning SubDirectories when building a WireMockContainer [feature]
- [#1140](https://github.com/WireMock-Net/WireMock.Net/issues/1140) - WireMock.Org nullable properties and defaults [bug]
# 1.5.60 (09 July 2024)
-- [#1128](https://github.com/WireMock-Net/WireMock.Net/pull/1128) - Add Handlebars.Net.Helpers.Xslt [feature] contributed by [StefH](https://github.com/StefH)
-- [#1130](https://github.com/WireMock-Net/WireMock.Net/pull/1130) - Add AdminPath to WireMockServerSettings [feature] contributed by [StefH](https://github.com/StefH)
-- [#1132](https://github.com/WireMock-Net/WireMock.Net/pull/1132) - Multipart Matcher Fix [bug] contributed by [rmeshksar](https://github.com/rmeshksar)
-- [#1134](https://github.com/WireMock-Net/WireMock.Net/pull/1134) - Remove some files and folders [refactor] contributed by [StefH](https://github.com/StefH)
- [#1119](https://github.com/WireMock-Net/WireMock.Net/issues/1119) - Error in RequestMessageMultiPartMatcher [bug]
- [#1121](https://github.com/WireMock-Net/WireMock.Net/issues/1121) - XML transformation [feature]
-# 1.5.59 (26 June 2024)
-- [#1127](https://github.com/WireMock-Net/WireMock.Net/pull/1127) - Made changes to accommodate breaking change in testcontainers-dotnet 3.9 [feature] contributed by [epDugas](https://github.com/epDugas)
-
# 1.5.58 (08 June 2024)
-- [#1116](https://github.com/WireMock-Net/WireMock.Net/pull/1116) - Add some methods to the BodyModelBuilder [feature] contributed by [StefH](https://github.com/StefH)
- [#1117](https://github.com/WireMock-Net/WireMock.Net/issues/1117) - AbstractJsonPartialMatcher: Regex Value is Uppercased when IgnoreCase is set to true [bug]
-# 1.5.57 (04 June 2024)
-- [#1113](https://github.com/WireMock-Net/WireMock.Net/pull/1113) - Add some Extension methods to IWireMockAdminApi [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.56 (03 June 2024)
-- [#1111](https://github.com/WireMock-Net/WireMock.Net/pull/1111) - Fix Request.Create().WithBodyAsJson(...) [bug] contributed by [StefH](https://github.com/StefH)
-- [#1112](https://github.com/WireMock-Net/WireMock.Net/pull/1112) - Add "/__admin/health" endpoint [feature] contributed by [StefH](https://github.com/StefH)
- [#1110](https://github.com/WireMock-Net/WireMock.Net/issues/1110) - Connection prematurely closed BEFORE response [bug]
-# 1.5.55 (22 May 2024)
-- [#1107](https://github.com/WireMock-Net/WireMock.Net/pull/1107) - When only Port is provided, bind to * (Fixes #1100) [bug] contributed by [StefH](https://github.com/StefH)
-
-# 1.5.54 (18 May 2024)
-- [#1100](https://github.com/WireMock-Net/WireMock.Net/pull/1100) - Add support to bind to ip-address instead of only localhost [feature] contributed by [StefH](https://github.com/StefH)
-- [#1104](https://github.com/WireMock-Net/WireMock.Net/pull/1104) - Use try..catch to set encoding in WireMockConsoleLogger [feature] contributed by [asherber](https://github.com/asherber)
-
# 1.5.53 (08 May 2024)
-- [#1093](https://github.com/WireMock-Net/WireMock.Net/pull/1093) - Update Handlebars.Net [feature] contributed by [StefH](https://github.com/StefH)
-- [#1101](https://github.com/WireMock-Net/WireMock.Net/pull/1101) - Fix MappingConverter to support Body with JsonMatcher [bug] contributed by [StefH](https://github.com/StefH)
- [#1095](https://github.com/WireMock-Net/WireMock.Net/issues/1095) - When using C# code generation WithBody() matcher is not generated for POST Request [bug]
# 1.5.52 (06 April 2024)
-- [#1091](https://github.com/WireMock-Net/WireMock.Net/pull/1091) - Add RegEx support to JsonMatcher [feature] contributed by [StefH](https://github.com/StefH)
- [#1088](https://github.com/WireMock-Net/WireMock.Net/issues/1088) - Regex support for JsonMatcher [feature]
# 1.5.51 (20 March 2024)
-- [#1085](https://github.com/WireMock-Net/WireMock.Net/pull/1085) - Fix FluentAssertions (actual body is not displayed in error message) [bug] contributed by [StefH](https://github.com/StefH)
- [#1084](https://github.com/WireMock-Net/WireMock.Net/issues/1084) - FluentAssertions - Actual body is not displayed in error message when using Json Body [bug]
# 1.5.50 (12 March 2024)
-- [#1080](https://github.com/WireMock-Net/WireMock.Net/pull/1080) - Fix FluentAssertions on Header(s) [bug] contributed by [StefH](https://github.com/StefH)
-- [#1082](https://github.com/WireMock-Net/WireMock.Net/pull/1082) - Make WireMockAssertions extendable [feature] contributed by [StefH](https://github.com/StefH)
- [#1074](https://github.com/WireMock-Net/WireMock.Net/issues/1074) - FluentAssertions extensions do not filter headers correctly [bug]
- [#1075](https://github.com/WireMock-Net/WireMock.Net/issues/1075) - FluentAssertions extensions are not open for extension [feature]
# 1.5.49 (06 March 2024)
-- [#1069](https://github.com/WireMock-Net/WireMock.Net/pull/1069) - Extend TypeLoader [feature] contributed by [StefH](https://github.com/StefH)
-- [#1078](https://github.com/WireMock-Net/WireMock.Net/pull/1078) - Upgrade ProtoBufJsonConverter to fix issue with dot(s) in package name [bug] contributed by [StefH](https://github.com/StefH)
- [#1077](https://github.com/WireMock-Net/WireMock.Net/issues/1077) - ProtoBufMatcher not working when proto package name contains dots [bug]
-# 1.5.48 (22 February 2024)
-- [#1047](https://github.com/WireMock-Net/WireMock.Net/pull/1047) - Add Grpc ProtoBuf support (request-response) [feature] contributed by [StefH](https://github.com/StefH)
-- [#1058](https://github.com/WireMock-Net/WireMock.Net/pull/1058) - Fix some SonarCloud issues [refactor] contributed by [StefH](https://github.com/StefH)
-
# 1.5.47 (25 January 2024)
-- [#1049](https://github.com/WireMock-Net/WireMock.Net/pull/1049) - Add WithoutHeader to WireMock.FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
-- [#1053](https://github.com/WireMock-Net/WireMock.Net/pull/1053) - [Snyk] Security upgrade Microsoft.IdentityModel.Protocols.OpenIdConnect from 6.12.2 to 6.34.0 [security] contributed by [StefH](https://github.com/StefH)
-- [#1057](https://github.com/WireMock-Net/WireMock.Net/pull/1057) - Pin the version from Testcontainers to 3.7.0 in WireMock.Net.Testcontainers [bug] contributed by [StefH](https://github.com/StefH)
- [#1048](https://github.com/WireMock-Net/WireMock.Net/issues/1048) - WithoutHeader fluent assertion [feature]
- [#1054](https://github.com/WireMock-Net/WireMock.Net/issues/1054) - WireMock.Net 1.5.46 is incompatible with TestContainers 3.7.0 (issue 1) [bug]
- [#1059](https://github.com/WireMock-Net/WireMock.Net/issues/1059) - WireMock.Net 1.5.46 is incompatible with TestContainers 3.7.0 (issue 2) [bug]
-# 1.5.46 (23 December 2023)
-- [#1044](https://github.com/WireMock-Net/WireMock.Net/pull/1044) - WireMockServerSettingsParser [refactor] contributed by [StefH](https://github.com/StefH)
-- [#1046](https://github.com/WireMock-Net/WireMock.Net/pull/1046) - Change FindRequestByMappingGuidAsync to return a collection of entries contributed by [tlevesque-ueat](https://github.com/tlevesque-ueat)
-
# 1.5.45 (21 December 2023)
-- [#1036](https://github.com/WireMock-Net/WireMock.Net/pull/1036) - Update Handlebars Transformer logic (ReplaceNodeOptions) [feature] contributed by [StefH](https://github.com/StefH)
-- [#1043](https://github.com/WireMock-Net/WireMock.Net/pull/1043) - FindRequestByMappingGuidAsync [feature] contributed by [StefH](https://github.com/StefH)
- [#1039](https://github.com/WireMock-Net/WireMock.Net/issues/1039) - [Admin API] Find a request that matched a given mapping [feature]
# 1.5.44 (14 December 2023)
-- [#1040](https://github.com/WireMock-Net/WireMock.Net/pull/1040) - Implement prefix for saved mapping file [feature] contributed by [MindaugasLaganeckas](https://github.com/MindaugasLaganeckas)
- [#1033](https://github.com/WireMock-Net/WireMock.Net/issues/1033) - How to get a Random Long? [bug]
- [#1037](https://github.com/WireMock-Net/WireMock.Net/issues/1037) - Make mapping filenames more user friendly [feature]
# 1.5.43 (11 December 2023)
-- [#1026](https://github.com/WireMock-Net/WireMock.Net/pull/1026) - Add ProxyUrlReplaceSettings to Response [feature] contributed by [StefH](https://github.com/StefH)
-- [#1038](https://github.com/WireMock-Net/WireMock.Net/pull/1038) - Proxy all requests - even a repeated one [feature] contributed by [sameena-ops](https://github.com/sameena-ops)
- [#592](https://github.com/WireMock-Net/WireMock.Net/issues/592) - Proxy all requests - even a repeated one [feature]
- [#1024](https://github.com/WireMock-Net/WireMock.Net/issues/1024) - Scenario with proxy not removing route prefix [feature]
# 1.5.42 (09 December 2023)
-- [#1023](https://github.com/WireMock-Net/WireMock.Net/pull/1023) - Fix Mapping[] for WireMock.Org REST API [bug] contributed by [StefH](https://github.com/StefH)
-- [#1031](https://github.com/WireMock-Net/WireMock.Net/pull/1031) - Calling Reset also resets the scenarios [bug] contributed by [StefH](https://github.com/StefH)
-- [#1034](https://github.com/WireMock-Net/WireMock.Net/pull/1034) - Workaround for: Random.Generate Type="Long" [bug] contributed by [StefH](https://github.com/StefH)
- [#1021](https://github.com/WireMock-Net/WireMock.Net/issues/1021) - GetAdminMappingsResult in WireMock.Org.Abstractions should contain list of mappings [bug]
- [#1030](https://github.com/WireMock-Net/WireMock.Net/issues/1030) - Reset resets only mappings and logentries, not scenarios. [bug]
# 1.5.41 (04 December 2023)
-- [#1012](https://github.com/WireMock-Net/WireMock.Net/pull/1012) - GraphQL - custom scalar support [feature] contributed by [StefH](https://github.com/StefH)
-- [#1018](https://github.com/WireMock-Net/WireMock.Net/pull/1018) - Add .NET 8 [feature] contributed by [StefH](https://github.com/StefH)
- [#984](https://github.com/WireMock-Net/WireMock.Net/issues/984) - GraphQL Schema validation with custom scalars [feature]
-# 1.5.40 (07 November 2023)
-- [#1011](https://github.com/WireMock-Net/WireMock.Net/pull/1011) - GraphQL - add support for standard scalar types in the schema [feature] contributed by [StefH](https://github.com/StefH)
-- [#1014](https://github.com/WireMock-Net/WireMock.Net/pull/1014) - FluentAssertions - WithBody and WithBodyAsJson and WithBodyAsBytes contributed by [StefH](https://github.com/StefH)
-
# 1.5.39 (09 October 2023)
-- [#1006](https://github.com/WireMock-Net/WireMock.Net/pull/1006) - Fix RequestMessageParamMatcher : RejectOnMatch [bug] contributed by [StefH](https://github.com/StefH)
- [#997](https://github.com/WireMock-Net/WireMock.Net/issues/997) - JmesPathMatcher or and MatchOperator working in version 1.5.34 but not 1.5.35 [bug]
-# 1.5.38 (02 October 2023)
-- [#1005](https://github.com/WireMock-Net/WireMock.Net/pull/1005) - Support for xml namespaces in XPathMatcher [feature] contributed by [cal-schleupen](https://github.com/cal-schleupen)
-
# 1.5.37 (27 September 2023)
-- [#1004](https://github.com/WireMock-Net/WireMock.Net/pull/1004) - Fix MappingModel to map IgnoreCase and RejectOnMatch for Headers, Cookies and Parameters [bug] contributed by [StefH](https://github.com/StefH)
- [#1003](https://github.com/WireMock-Net/WireMock.Net/issues/1003) - Store Mapping per POST request ignores "IgnoreCase" property of HeaderModel [bug]
# 1.5.36 (21 September 2023)
-- [#986](https://github.com/WireMock-Net/WireMock.Net/pull/986) - Write logging in case a Matcher throws an exception [feature] contributed by [StefH](https://github.com/StefH)
-- [#996](https://github.com/WireMock-Net/WireMock.Net/pull/996) - Remove dependency on Microsoft.AspNet.WebApi.Client [feature] contributed by [StefH](https://github.com/StefH)
-- [#1002](https://github.com/WireMock-Net/WireMock.Net/pull/1002) - Fixed logic for SaveUnmatchedRequests [bug] contributed by [StefH](https://github.com/StefH)
- [#974](https://github.com/WireMock-Net/WireMock.Net/issues/974) - HttpClient extension methods causes ambiguous invocations in .NET 7 [bug]
- [#1001](https://github.com/WireMock-Net/WireMock.Net/issues/1001) - SaveUnmatchedRequests stopped working [bug]
-# 1.5.35 (19 August 2023)
-- [#993](https://github.com/WireMock-Net/WireMock.Net/pull/993) - Update JSONPathMatcher.cs to cover the string path selection to a child contributed by [DayLightDancer](https://github.com/DayLightDancer)
-
# 1.5.34 (04 August 2023)
-- [#989](https://github.com/WireMock-Net/WireMock.Net/pull/989) - Fix MimeKitLite NuGet include [bug] contributed by [StefH](https://github.com/StefH)
- [#988](https://github.com/WireMock-Net/WireMock.Net/issues/988) - v1.5.33 Returns always StatusCode 500 [bug]
# 1.5.33 (03 August 2023)
-- [#972](https://github.com/WireMock-Net/WireMock.Net/pull/972) - JsonPartialMatcher - match guid and string contributed by [timurnes](https://github.com/timurnes)
-- [#976](https://github.com/WireMock-Net/WireMock.Net/pull/976) - Upgrade to Handlebars.Net.Helpers 2.4.0 to update XPath.SelectTokens and XPath.EvaluateToString [feature] contributed by [StefH](https://github.com/StefH)
-- [#981](https://github.com/WireMock-Net/WireMock.Net/pull/981) - Add MultiPart/MimePart Request Matcher [feature] contributed by [StefH](https://github.com/StefH)
- [#968](https://github.com/WireMock-Net/WireMock.Net/issues/968) - Using request multipart in response template [feature]
- [#969](https://github.com/WireMock-Net/WireMock.Net/issues/969) - Multipart validation [feature]
- [#970](https://github.com/WireMock-Net/WireMock.Net/issues/970) - Loop through xml elements in handlebars template [feature]
- [#971](https://github.com/WireMock-Net/WireMock.Net/issues/971) - JsonPartialMatcher - match guid and string [feature]
# 1.5.32 (15 July 2023)
-- [#966](https://github.com/WireMock-Net/WireMock.Net/pull/966) - Fixed JsonPathMatcher to match nested objects [bug] contributed by [StefH](https://github.com/StefH)
- [#965](https://github.com/WireMock-Net/WireMock.Net/issues/965) - JsonPathMatcher does not match json body nested objects [bug]
- [#967](https://github.com/WireMock-Net/WireMock.Net/issues/967) - ⭐10 million downloads ! ⭐ [feature]
-# 1.5.31 (08 July 2023)
-- [#964](https://github.com/WireMock-Net/WireMock.Net/pull/964) - Add GraphQL Schema matching [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.30 (28 June 2023)
-- [#959](https://github.com/WireMock-Net/WireMock.Net/pull/959) - Fixed logic for FluentAssertions WithHeader [bug] contributed by [StefH](https://github.com/StefH)
-- [#962](https://github.com/WireMock-Net/WireMock.Net/pull/962) - Bump System.Linq.Dynamic.Core from 1.2.23 to 1.3.0 in /examples/WireMock.Net.Console.Net472.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#963](https://github.com/WireMock-Net/WireMock.Net/pull/963) - Bump System.Linq.Dynamic.Core from 1.2.23 to 1.3.0 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#958](https://github.com/WireMock-Net/WireMock.Net/issues/958) - [FluentAssertions] Should().HaveReceivedACall().WithHeader() only checks the first header with the matching key. [bug]
# 1.5.29 (22 June 2023)
-- [#954](https://github.com/WireMock-Net/WireMock.Net/pull/954) - Support setting WireMockServerSettings via Environment [feature] contributed by [StefH](https://github.com/StefH)
-- [#955](https://github.com/WireMock-Net/WireMock.Net/pull/955) - Fix some SonarCloud issues [refactor] contributed by [StefH](https://github.com/StefH)
- [#953](https://github.com/WireMock-Net/WireMock.Net/issues/953) - How to use environment variable [feature]
-# 1.5.28 (11 June 2023)
-- [#948](https://github.com/WireMock-Net/WireMock.Net/pull/948) - WireMock.Net.Testcontainers [feature] contributed by [StefH](https://github.com/StefH)
-- [#951](https://github.com/WireMock-Net/WireMock.Net/pull/951) - Allow setting the Content-Length header for a HTTP method HEAD [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.27 (03 June 2023)
-- [#946](https://github.com/WireMock-Net/WireMock.Net/pull/946) - Add warning logging when sending a request to a Webhook does not return status 200 [feature] contributed by [StefH](https://github.com/StefH)
-- [#949](https://github.com/WireMock-Net/WireMock.Net/pull/949) - Add ".NET Framework 4.7" to WireMock.Net.FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
- [#928](https://github.com/WireMock-Net/WireMock.Net/issues/928) - TypeLoadException when using WithHeader method. [bug]
- [#945](https://github.com/WireMock-Net/WireMock.Net/issues/945) - Webhook logging [feature]
# 1.5.26 (25 May 2023)
-- [#939](https://github.com/WireMock-Net/WireMock.Net/pull/939) - WireMockMiddleware should use HandleRequestsSynchronously correctly [bug] contributed by [StefH](https://github.com/StefH)
-- [#940](https://github.com/WireMock-Net/WireMock.Net/pull/940) - Code generator improvements contributed by [cezarypiatek](https://github.com/cezarypiatek)
-- [#942](https://github.com/WireMock-Net/WireMock.Net/pull/942) - Add GetParameter method to IRequestMessage [feature] contributed by [StefH](https://github.com/StefH)
- [#941](https://github.com/WireMock-Net/WireMock.Net/issues/941) - RequestMessage.GetParameter method missing from IRequestMessage interface [feature]
-# 1.5.25 (13 May 2023)
-- [#934](https://github.com/WireMock-Net/WireMock.Net/pull/934) - Code generator improvements [feature] contributed by [cezarypiatek](https://github.com/cezarypiatek)
-
-# 1.5.24 (07 May 2023)
-- [#926](https://github.com/WireMock-Net/WireMock.Net/pull/926) - Fix C# mapping code generator for header names [bug] contributed by [cezarypiatek](https://github.com/cezarypiatek)
-- [#927](https://github.com/WireMock-Net/WireMock.Net/pull/927) - Enrich generated code with status code [feature] contributed by [cezarypiatek](https://github.com/cezarypiatek)
-- [#930](https://github.com/WireMock-Net/WireMock.Net/pull/930) - Update C# mapping code generator for WithStatusCode [feature] contributed by [StefH](https://github.com/StefH)
-- [#931](https://github.com/WireMock-Net/WireMock.Net/pull/931) - Add property 'IsStartedWithAdminInterface' to 'IWireMockServer' [feature] contributed by [StefH](https://github.com/StefH)
-- [#933](https://github.com/WireMock-Net/WireMock.Net/pull/933) - C# code generator improvements [feature] contributed by [cezarypiatek](https://github.com/cezarypiatek)
-
-# 1.5.23 (23 April 2023)
-- [#922](https://github.com/WireMock-Net/WireMock.Net/pull/922) - Add WithProbability [feature] contributed by [StefH](https://github.com/StefH)
-- [#924](https://github.com/WireMock-Net/WireMock.Net/pull/924) - Allow removal of prefix when proxying to another server (#630) [feature] contributed by [nudejustin](https://github.com/nudejustin)
-- [#925](https://github.com/WireMock-Net/WireMock.Net/pull/925) - Add IgnoreCase option to ProxyUrlReplaceSettings [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.22 (08 April 2023)
-- [#914](https://github.com/WireMock-Net/WireMock.Net/pull/914) - #912 add excluded params to proxy mapping [feature] contributed by [walidhaidarii](https://github.com/walidhaidarii)
-- [#916](https://github.com/WireMock-Net/WireMock.Net/pull/916) - Include WireMockOpenApiParser project [feature] contributed by [StefH](https://github.com/StefH)
- [#912](https://github.com/WireMock-Net/WireMock.Net/issues/912) - Feature: adding excluded params to proxy and records settings [feature]
# 1.5.21 (22 March 2023)
-- [#908](https://github.com/WireMock-Net/WireMock.Net/pull/908) - RequestBuilder : add WithBodyAsJson and WithBody (with IJsonConverter) [feature] contributed by [StefH](https://github.com/StefH)
-- [#911](https://github.com/WireMock-Net/WireMock.Net/pull/911) - Fixed QueryStringParser for UrlEncoded values [bug] contributed by [StefH](https://github.com/StefH)
- [#901](https://github.com/WireMock-Net/WireMock.Net/issues/901) - Matching one form-urlencoded value [feature]
# 1.5.20 (19 March 2023)
-- [#905](https://github.com/WireMock-Net/WireMock.Net/pull/905) - Add DeserializeFormUrl Encoded to the settings [feature] contributed by [StefH](https://github.com/StefH)
-- [#907](https://github.com/WireMock-Net/WireMock.Net/pull/907) - Fix issue with application/x-www-form-urlencoded and ExactMatcher [bug] contributed by [StefH](https://github.com/StefH)
- [#906](https://github.com/WireMock-Net/WireMock.Net/issues/906) - Upgrade to 1.5.19 breaks a form data test [bug]
-# 1.5.19 (17 March 2023)
-- [#903](https://github.com/WireMock-Net/WireMock.Net/pull/903) - Add WithBody with IDictionary (form-urlencoded values) [feature] contributed by [StefH](https://github.com/StefH)
-- [#904](https://github.com/WireMock-Net/WireMock.Net/pull/904) - Update Handlebars.Net.Helpers to 2.3.15 [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.18 (09 March 2023)
-- [#893](https://github.com/WireMock-Net/WireMock.Net/pull/893) - Add 'Data' to response which can be used during transforming the response [feature] contributed by [StefH](https://github.com/StefH)
-- [#896](https://github.com/WireMock-Net/WireMock.Net/pull/896) - Bump Microsoft.Owin from 2.0.2 to 4.2.2 in /examples/WireMock.Net.Service [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#900](https://github.com/WireMock-Net/WireMock.Net/pull/900) - ProxySettings : Add logic to not save some requests depending on HttpMethods [feature] contributed by [StefH](https://github.com/StefH)
- [#897](https://github.com/WireMock-Net/WireMock.Net/issues/897) - WebHostBuilder.ConfigureServices method not found when using nunit3testadapter 4.4.0 [bug]
- [#899](https://github.com/WireMock-Net/WireMock.Net/issues/899) - Ignore OPTIONS request when using proxyandrecord [feature]
-# 1.5.17 (25 February 2023)
-- [#881](https://github.com/WireMock-Net/WireMock.Net/pull/881) - Add WithBodyAsJson builder method with accepts a Func [feature] contributed by [StefH](https://github.com/StefH)
-- [#890](https://github.com/WireMock-Net/WireMock.Net/pull/890) - AdminApiMappingBuilder [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.16 (01 February 2023)
-- [#880](https://github.com/WireMock-Net/WireMock.Net/pull/880) - Add `WithProxy(string proxyUrl, X509Certificate2 certificate)` [feature] contributed by [StefH](https://github.com/StefH)
- [#879](https://github.com/WireMock-Net/WireMock.Net/issues/879) - Possibility to pass a X509Certificate2 to WithProxy() or specifiy certificate loading options [feature]
-# 1.5.15 (29 January 2023)
-- [#878](https://github.com/WireMock-Net/WireMock.Net/pull/878) - Update REST Admin interface to support "Get Mapping(s) as C# Code" [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.14 (24 January 2023)
-- [#842](https://github.com/WireMock-Net/WireMock.Net/pull/842) - Generate C# code from Mapping [feature] contributed by [StefH](https://github.com/StefH)
-- [#869](https://github.com/WireMock-Net/WireMock.Net/pull/869) - Add MappingBuilder to build mappings in code and export to Models or JSON [feature] contributed by [StefH](https://github.com/StefH)
-- [#871](https://github.com/WireMock-Net/WireMock.Net/pull/871) - Add UseWebhooksFireAndForget to Server ConvertMapping [bug] contributed by [ggradnig](https://github.com/ggradnig)
-- [#872](https://github.com/WireMock-Net/WireMock.Net/pull/872) - Fix unsubscribe from LogEntriesChanged event handler [bug] contributed by [StefH](https://github.com/StefH)
-- [#875](https://github.com/WireMock-Net/WireMock.Net/pull/875) - Fix Self referencing loop detected for property [bug] contributed by [eseneckiy](https://github.com/eseneckiy)
- [#701](https://github.com/WireMock-Net/WireMock.Net/issues/701) - Allow to create MappingModel from c# to be able to configure local and remote mocks similarly [feature]
- [#867](https://github.com/WireMock-Net/WireMock.Net/issues/867) - Can I build mappings with code and save them to JSON-file without starting server [feature]
- [#870](https://github.com/WireMock-Net/WireMock.Net/issues/870) - Can not unsubscribe from LogEntriesChanged event. [bug]
# 1.5.13 (11 December 2022)
-- [#858](https://github.com/WireMock-Net/WireMock.Net/pull/858) - Update Transformer functionality to return value instead of string [feature] contributed by [StefH](https://github.com/StefH)
-- [#859](https://github.com/WireMock-Net/WireMock.Net/pull/859) - Add UpdatedAt property to Mapping [feature] contributed by [StefH](https://github.com/StefH)
-- [#862](https://github.com/WireMock-Net/WireMock.Net/pull/862) - Add client certificate support [feature] contributed by [billybraga](https://github.com/billybraga)
-- [#863](https://github.com/WireMock-Net/WireMock.Net/pull/863) - Update WireMockServer.CreateClient/CreateClients to include handlers [feature] contributed by [StefH](https://github.com/StefH)
- [#856](https://github.com/WireMock-Net/WireMock.Net/issues/856) - Inconsistent result with overlapping (duplicate) request [bug]
-# 1.5.12 (03 December 2022)
-- [#851](https://github.com/WireMock-Net/WireMock.Net/pull/851) - Fix Linux CI build + Fix opencover [feature] contributed by [StefH](https://github.com/StefH)
-- [#853](https://github.com/WireMock-Net/WireMock.Net/pull/853) - Add .Net 7 [feature] contributed by [StefH](https://github.com/StefH)
-- [#854](https://github.com/WireMock-Net/WireMock.Net/pull/854) - Fix logic for QueryParameterMultipleValueSupport [bug] contributed by [StefH](https://github.com/StefH)
-- [#857](https://github.com/WireMock-Net/WireMock.Net/pull/857) - Update some dependencies [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.11 (24 November 2022)
-- [#836](https://github.com/WireMock-Net/WireMock.Net/pull/836) - Add Settings.QueryParameterMultipleValueSupport [feature] contributed by [StefH](https://github.com/StefH)
-- [#848](https://github.com/WireMock-Net/WireMock.Net/pull/848) - Use try-catch when adding or removing logEntry [bug] contributed by [StefH](https://github.com/StefH)
- [#846](https://github.com/WireMock-Net/WireMock.Net/issues/846) - Exception ArgumentOutOfRangeException [bug]
-# 1.5.10 (06 November 2022)
-- [#843](https://github.com/WireMock-Net/WireMock.Net/pull/843) - Webhook Templating: Use the transformed URL to create the HttpRequestMessage contributed by [ggradnig](https://github.com/ggradnig)
-- [#845](https://github.com/WireMock-Net/WireMock.Net/pull/845) - Add WireMockNullLogger as valid commandline logger option [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.9 (29 October 2022)
-- [#828](https://github.com/WireMock-Net/WireMock.Net/pull/828) - Add setting to skip saving the string-response in the logging when using WithBody(Func...) [feature] contributed by [StefH](https://github.com/StefH)
-- [#832](https://github.com/WireMock-Net/WireMock.Net/pull/832) - Fixes for WireMock.Net.FluentAssertions (callcount behaviour) [feature] contributed by [StefH](https://github.com/StefH)
-- [#834](https://github.com/WireMock-Net/WireMock.Net/pull/834) - Support deleting / resetting a single scenario [feature] contributed by [StefH](https://github.com/StefH)
-- [#837](https://github.com/WireMock-Net/WireMock.Net/pull/837) - Bump Microsoft.AspNetCore.Server.Kestrel.Core from 2.1.7 to 2.1.25 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#838](https://github.com/WireMock-Net/WireMock.Net/pull/838) - Add option to ProxySettings to append guid to mapping file contributed by [StefH](https://github.com/StefH)
- [#826](https://github.com/WireMock-Net/WireMock.Net/issues/826) - Dynamic Body not to be cached when a Func is used to created the body [feature]
# 1.5.8 (16 October 2022)
-- [#816](https://github.com/WireMock-Net/WireMock.Net/pull/816) - Some fixes to WireMock.Net.Assertions [feature] contributed by [StefH](https://github.com/StefH)
-- [#817](https://github.com/WireMock-Net/WireMock.Net/pull/817) - ExactMatcher : IgnoreCase [feature] contributed by [StefH](https://github.com/StefH)
-- [#824](https://github.com/WireMock-Net/WireMock.Net/pull/824) - WebHook - Transform Url [feature] contributed by [StefH](https://github.com/StefH)
- [#814](https://github.com/WireMock-Net/WireMock.Net/issues/814) - WithHeader cannot handle multiple requests with the same header key values [bug]
- [#815](https://github.com/WireMock-Net/WireMock.Net/issues/815) - Why does UsingMethod check _callscount? [bug]
- [#822](https://github.com/WireMock-Net/WireMock.Net/issues/822) - Webhook with generic url, body and custom header values [feature]
# 1.5.7 (11 October 2022)
-- [#818](https://github.com/WireMock-Net/WireMock.Net/pull/818) - Add option to run the server on http & https [feature] contributed by [StefH](https://github.com/StefH)
-- [#821](https://github.com/WireMock-Net/WireMock.Net/pull/821) - Add UseDefinedRequestMatchers to ProxyAndRecordSettings [feature] contributed by [StefH](https://github.com/StefH)
-- [#823](https://github.com/WireMock-Net/WireMock.Net/pull/823) - Add implicit operators to WireMockList contributed by [StefH](https://github.com/StefH)
- [#819](https://github.com/WireMock-Net/WireMock.Net/issues/819) - Can I preserve Mapping title and matchers for proxy response? [feature]
# 1.5.6 (12 September 2022)
-- [#803](https://github.com/WireMock-Net/WireMock.Net/pull/803) - WebHook : UseFireAndForget + Delay [feature] contributed by [StefH](https://github.com/StefH)
- [#801](https://github.com/WireMock-Net/WireMock.Net/issues/801) - Webhook Delays [feature]
# 1.5.5 (03 September 2022)
-- [#798](https://github.com/WireMock-Net/WireMock.Net/pull/798) - Add support to use 'mapping' object in in reponse templating [feature] contributed by [StefH](https://github.com/StefH)
-- [#800](https://github.com/WireMock-Net/WireMock.Net/pull/800) - Bump Microsoft.Owin from 4.1.1 to 4.2.2 in /src/WireMock.Net (net46) [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#802](https://github.com/WireMock-Net/WireMock.Net/pull/802) - Add assertions for request methods contributed by [rafaelmfonseca](https://github.com/rafaelmfonseca)
- [#772](https://github.com/WireMock-Net/WireMock.Net/issues/772) - How to get matched mapping by HttpRequest or HttpRequestMessage [feature]
# 1.5.4 (24 August 2022)
-- [#778](https://github.com/WireMock-Net/WireMock.Net/pull/778) - Fix Proxying when StartAdminInterface=true [bug] contributed by [StefH](https://github.com/StefH)
-- [#781](https://github.com/WireMock-Net/WireMock.Net/pull/781) - Update some NuGet packages [feature] contributed by [StefH](https://github.com/StefH)
-- [#783](https://github.com/WireMock-Net/WireMock.Net/pull/783) - Fix WithBody when using Pact and added more nullable annotations [feature] contributed by [StefH](https://github.com/StefH)
-- [#787](https://github.com/WireMock-Net/WireMock.Net/pull/787) - Add support for PEM certificates contributed by [StefH](https://github.com/StefH)
-- [#789](https://github.com/WireMock-Net/WireMock.Net/pull/789) - Add support for Matcher.Pattern in Pact Body mapping [feature] contributed by [StefH](https://github.com/StefH)
-- [#790](https://github.com/WireMock-Net/WireMock.Net/pull/790) - Add Response.WithBody with IJsonConverter [feature] contributed by [StefH](https://github.com/StefH)
-- [#795](https://github.com/WireMock-Net/WireMock.Net/pull/795) - Add check for duplicate Guids when posting multiple mappings in one request contributed by [StefH](https://github.com/StefH)
-- [#797](https://github.com/WireMock-Net/WireMock.Net/pull/797) - Fix WithHeader when using RejectOnMatch [bug] contributed by [flts](https://github.com/flts)
- [#775](https://github.com/WireMock-Net/WireMock.Net/issues/775) - When "StartAdminInterface" is true then each time is generated new mapping from the proxy [bug]
- [#784](https://github.com/WireMock-Net/WireMock.Net/issues/784) - Response body is missing in generated pact file when IBodyResponseBuilder.WithBody is used [bug]
- [#785](https://github.com/WireMock-Net/WireMock.Net/issues/785) - Support for PEM certificates when using ssl [feature]
@@ -434,469 +214,210 @@
- [#796](https://github.com/WireMock-Net/WireMock.Net/issues/796) - RequestMessageHeaderMatcher with MatchBehaviour.RejectOnMatch reverses match results twice [bug]
# 1.5.3 (29 July 2022)
-- [#777](https://github.com/WireMock-Net/WireMock.Net/pull/777) - Update Scriban.Signed to version 5.5.0 [feature] contributed by [StefH](https://github.com/StefH)
- [#776](https://github.com/WireMock-Net/WireMock.Net/issues/776) - Update Scriban.Signed to support more functions, e.g math.random [feature]
-# 1.5.2 (24 July 2022)
-- [#769](https://github.com/WireMock-Net/WireMock.Net/pull/769) - Bump Microsoft.AspNetCore.Server.Kestrel.Core from 2.1.3 to 2.1.7 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#771](https://github.com/WireMock-Net/WireMock.Net/pull/771) - JsonPartialMatcher - support Regex [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.5.1 (08 July 2022)
-- [#762](https://github.com/WireMock-Net/WireMock.Net/pull/762) - Bump Newtonsoft.Json from 11.0.2 to 13.0.1 in /examples/WireMock.Net.WebApplication.NETCore2 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#763](https://github.com/WireMock-Net/WireMock.Net/pull/763) - Bump Newtonsoft.Json from 6.0.1 to 13.0.1 in /examples/WireMock.Net.Client.Net472 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#765](https://github.com/WireMock-Net/WireMock.Net/pull/765) - Update WireMock.Org.Abstractions and WireMock.Org.RestClient [feature] contributed by [StefH](https://github.com/StefH)
-- [#766](https://github.com/WireMock-Net/WireMock.Net/pull/766) - Bump Microsoft.AspNetCore.Http from 2.1.1 to 2.1.22 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#767](https://github.com/WireMock-Net/WireMock.Net/pull/767) - Rename (WireMock.Pact.Models.V2)-Request to PactRequest and -Response to PactResponse [feature] contributed by [StefH](https://github.com/StefH)
- [#764](https://github.com/WireMock-Net/WireMock.Net/issues/764) - Wrong mapping of method GetAdminMappingsAsync from IWireMockOrgApi [bug]
-# 1.5.0 (09 June 2022)
-- [#755](https://github.com/WireMock-Net/WireMock.Net/pull/755) - Add MatchOperator "Or", "And" and "Average" for patterns [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.43 (21 May 2022)
-- [#757](https://github.com/WireMock-Net/WireMock.Net/pull/757) - Log correct exception message when handling aggregate exceptions contributed by [siewers](https://github.com/siewers)
-- [#759](https://github.com/WireMock-Net/WireMock.Net/pull/759) - Add WireMock.Net.xUnit project [feature] contributed by [StefH](https://github.com/StefH)
- [#756](https://github.com/WireMock-Net/WireMock.Net/issues/756) - WireMockConsoleLogger aggregate exception handling bug? [bug]
- [#758](https://github.com/WireMock-Net/WireMock.Net/issues/758) - Add support for logging to an xUnit ITestOutputHelper [feature]
# 1.4.42 (13 May 2022)
-- [#748](https://github.com/WireMock-Net/WireMock.Net/pull/748) - Initial support for converting the mappings to a Pact(flow) json file [feature] contributed by [StefH](https://github.com/StefH)
-- [#749](https://github.com/WireMock-Net/WireMock.Net/pull/749) - Swagger support [feature] contributed by [StefH](https://github.com/StefH)
-- [#750](https://github.com/WireMock-Net/WireMock.Net/pull/750) - [Snyk] Security upgrade Newtonsoft.Json from 11.0.2 to 13.0.1 contributed by [snyk-bot](https://github.com/snyk-bot)
-- [#751](https://github.com/WireMock-Net/WireMock.Net/pull/751) - Update NuGets packages [feature] contributed by [StefH](https://github.com/StefH)
- [#741](https://github.com/WireMock-Net/WireMock.Net/issues/741) - Integrate with Pact [feature]
- [#753](https://github.com/WireMock-Net/WireMock.Net/issues/753) - FluentAssertions - assert the server has not received a call [feature]
# 1.4.41 (21 April 2022)
-- [#746](https://github.com/WireMock-Net/WireMock.Net/pull/746) - Allow Timeout.InfiniteTimeSpan for WithDelay [feature] contributed by [StefH](https://github.com/StefH)
-- [#747](https://github.com/WireMock-Net/WireMock.Net/pull/747) - Update the logic for ProxyAndRecord contributed by [StefH](https://github.com/StefH)
- [#744](https://github.com/WireMock-Net/WireMock.Net/issues/744) - System.ArgumentOutOfRangeException when Timeout.InfiniteTimeSpan used as an argument for IResponseBuilder.WithDelay() [bug]
-# 1.4.40 (26 March 2022)
-- [#740](https://github.com/WireMock-Net/WireMock.Net/pull/740) - Add Port and Url property to WireMockServer + upgrade System.Linq.Dynamic.Core [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.4.39 (25 March 2022)
-- [#739](https://github.com/WireMock-Net/WireMock.Net/pull/739) - Upgrade NuGet for RandomDataGenerator.Net to 1.0.14 contributed by [StefH](https://github.com/StefH)
-
-# 1.4.38 (11 March 2022)
-- [#736](https://github.com/WireMock-Net/WireMock.Net/pull/736) - Remove interface for all Setting classes [feature] contributed by [StefH](https://github.com/StefH)
-- [#737](https://github.com/WireMock-Net/WireMock.Net/pull/737) - Add WireMock.Net.WebApplication.NET6 example contributed by [StefH](https://github.com/StefH)
-
# 1.4.37 (02 March 2022)
-- [#730](https://github.com/WireMock-Net/WireMock.Net/pull/730) - Fixed bug "dotnet nuget push -n" [bug] contributed by [StefH](https://github.com/StefH)
-- [#732](https://github.com/WireMock-Net/WireMock.Net/pull/732) - Make X509CertificatePassword optional [feature] contributed by [StefH](https://github.com/StefH)
-- [#733](https://github.com/WireMock-Net/WireMock.Net/pull/733) - Fix FileSystemWatcher [bug] contributed by [StefH](https://github.com/StefH)
- [#726](https://github.com/WireMock-Net/WireMock.Net/issues/726) - Wiremock - WatchStaticMappings only works until the first request is made [bug]
-# 1.4.36 (25 February 2022)
-- [#728](https://github.com/WireMock-Net/WireMock.Net/pull/728) - Update NuGet packages [feature] contributed by [StefH](https://github.com/StefH)
-- [#729](https://github.com/WireMock-Net/WireMock.Net/pull/729) - BodyAsFile should use BodyAsFileIsCached value [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.4.35 (09 February 2022)
-- [#722](https://github.com/WireMock-Net/WireMock.Net/pull/722) - Fixed 'Response BodyAsJson with JArray does not work' [bug] contributed by [StefH](https://github.com/StefH)
- [#721](https://github.com/WireMock-Net/WireMock.Net/issues/721) - Response BodyAsJson with array does not work [bug]
# 1.4.34 (27 January 2022)
-- [#716](https://github.com/WireMock-Net/WireMock.Net/pull/716) - MatcherMapper : Always use Pattern [bug] contributed by [StefH](https://github.com/StefH)
- [#715](https://github.com/WireMock-Net/WireMock.Net/issues/715) - Record request mapping outputs JsonMatcher with Patterns instead of Pattern [bug]
-# 1.4.33 (24 January 2022)
-- [#714](https://github.com/WireMock-Net/WireMock.Net/pull/714) - Add support for Cors [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.4.32 (17 January 2022)
-- [#713](https://github.com/WireMock-Net/WireMock.Net/pull/713) - Added support of custom matchers in static mappings contributed by [levanoz](https://github.com/levanoz)
-
-# 1.4.31 (06 January 2022)
-- [#706](https://github.com/WireMock-Net/WireMock.Net/pull/706) - Provide open api schema to dynamic examples generator so you can generate accurate data [feature] contributed by [brunotarghetta](https://github.com/brunotarghetta)
-- [#707](https://github.com/WireMock-Net/WireMock.Net/pull/707) - Use NuGet "Stef.Validation" [feature] contributed by [StefH](https://github.com/StefH)
-- [#710](https://github.com/WireMock-Net/WireMock.Net/pull/710) - Add ReplaceNodeOption flag [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.30 (25 December 2021)
-- [#703](https://github.com/WireMock-Net/WireMock.Net/pull/703) - SaveUnmatchedRequests [feature] contributed by [StefH](https://github.com/StefH)
-- [#704](https://github.com/WireMock-Net/WireMock.Net/pull/704) - Add .ConfigureAwait(false); to the await Task calls [bug] contributed by [StefH](https://github.com/StefH)
- [#534](https://github.com/WireMock-Net/WireMock.Net/issues/534) - Mock server not answer if integrated in Xamarin UITest project [bug]
- [#567](https://github.com/WireMock-Net/WireMock.Net/issues/567) - Can't start WireMock.Net server in Xamarin.UITest project (.NET Framework 4.7.2) on MacOS [bug]
- [#685](https://github.com/WireMock-Net/WireMock.Net/issues/685) - GuidWildcardMatcher to match on GUIDs [feature]
-# 1.4.29 (12 December 2021)
-- [#699](https://github.com/WireMock-Net/WireMock.Net/pull/699) - GUID Pattern support in RegexMatcher contributed by [brogdogg](https://github.com/brogdogg)
-- [#700](https://github.com/WireMock-Net/WireMock.Net/pull/700) - RegexExtended in settings [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.28 (01 December 2021)
-- [#686](https://github.com/WireMock-Net/WireMock.Net/pull/686) - [Snyk] Security upgrade Microsoft.Owin from 4.0.0 to 4.1.1 [dependencies] contributed by [snyk-bot](https://github.com/snyk-bot)
-- [#688](https://github.com/WireMock-Net/WireMock.Net/pull/688) - Bump System.Text.Encodings.Web from 4.5.0 to 4.5.1 in /examples/WireMock.Net.Console.Net472.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#689](https://github.com/WireMock-Net/WireMock.Net/pull/689) - Upgrade some NuGet's (Codecov, coverlet, Moq and NFluent) [dependencies] contributed by [StefH](https://github.com/StefH)
-- [#691](https://github.com/WireMock-Net/WireMock.Net/pull/691) - Update the OpenApiPathsMapper to handle Value/Wildcard [feature] contributed by [StefH](https://github.com/StefH)
-- [#694](https://github.com/WireMock-Net/WireMock.Net/pull/694) - RamlToOpenAPI updated to 0.5.0 [feature] contributed by [mcheguini](https://github.com/mcheguini)
-- [#695](https://github.com/WireMock-Net/WireMock.Net/pull/695) - Allow configure IgnoreCase in settings [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#696](https://github.com/WireMock-Net/WireMock.Net/pull/696) - Filter required property in headers, query params, request body [feature] contributed by [leolplex](https://github.com/leolplex)
- [#666](https://github.com/WireMock-Net/WireMock.Net/issues/666) - Example is not working as expected [bug]
- [#692](https://github.com/WireMock-Net/WireMock.Net/issues/692) - Case insensitive and ignoring optional path and header parameters in OpenApiPathsMapper [feature]
-# 1.4.27 (17 November 2021)
-- [#678](https://github.com/WireMock-Net/WireMock.Net/pull/678) - Support RequestBody [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#680](https://github.com/WireMock-Net/WireMock.Net/pull/680) - Support examples in properties [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#681](https://github.com/WireMock-Net/WireMock.Net/pull/681) - Support enums in properties [feature] contributed by [leolplex](https://github.com/leolplex)
-
-# 1.4.26 (04 November 2021)
-- [#670](https://github.com/WireMock-Net/WireMock.Net/pull/670) - Improve method MapSchemaToObject to support array and object [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#673](https://github.com/WireMock-Net/WireMock.Net/pull/673) - Support examples random data generation contributed by [leolplex](https://github.com/leolplex)
-- [#675](https://github.com/WireMock-Net/WireMock.Net/pull/675) - Support basepath from servers contributed by [leolplex](https://github.com/leolplex)
-- [#676](https://github.com/WireMock-Net/WireMock.Net/pull/676) - Fix random generate data in url no spaces [feature] contributed by [leolplex](https://github.com/leolplex)
-
-# 1.4.25 (27 October 2021)
-- [#661](https://github.com/WireMock-Net/WireMock.Net/pull/661) - Add TimeSettings (Start, End and TTL) [feature] contributed by [StefH](https://github.com/StefH)
-- [#664](https://github.com/WireMock-Net/WireMock.Net/pull/664) - Support Array in OpenApiParser [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#667](https://github.com/WireMock-Net/WireMock.Net/pull/667) - Add JsonPartialWildcardMatcher [feature] contributed by [StefH](https://github.com/StefH)
-- [#669](https://github.com/WireMock-Net/WireMock.Net/pull/669) - Support Schema Example and Support AllOf in definitions [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.4.24 (20 October 2021)
-- [#637](https://github.com/WireMock-Net/WireMock.Net/pull/637) - Add support for AzureAD authentication for REST admin interface [feature] contributed by [StefH](https://github.com/StefH)
-- [#643](https://github.com/WireMock-Net/WireMock.Net/pull/643) - Support edge case: first object, next an array. [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#644](https://github.com/WireMock-Net/WireMock.Net/pull/644) - Mapping headers in OpenAPI [feature] contributed by [leolplex](https://github.com/leolplex)
-- [#649](https://github.com/WireMock-Net/WireMock.Net/pull/649) - Refactor method name MapHeaders and httpStatusCode contributed by [leolplex](https://github.com/leolplex)
-- [#651](https://github.com/WireMock-Net/WireMock.Net/pull/651) - Implement PatternAsFile for StringMatcher [feature] contributed by [StefH](https://github.com/StefH)
-- [#654](https://github.com/WireMock-Net/WireMock.Net/pull/654) - Update NotNullOrEmptyMatcher to also implement IStringMatcher [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.23 (27 September 2021)
-- [#635](https://github.com/WireMock-Net/WireMock.Net/pull/635) - WireMock.Net.FluentAssertions : upgrade to latest FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
- [#634](https://github.com/WireMock-Net/WireMock.Net/issues/634) - Upgrade to latest FluentAssertions [bug]
-# 1.4.22 (22 September 2021)
-- [#633](https://github.com/WireMock-Net/WireMock.Net/pull/633) - Implement Random Delay [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.4.21 (16 September 2021)
-- [#631](https://github.com/WireMock-Net/WireMock.Net/pull/631) - Add WireMock.org RestClient [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.20 (06 August 2021)
-- [#628](https://github.com/WireMock-Net/WireMock.Net/pull/628) - Fix issue with FluentBuilder [bug] contributed by [StefH](https://github.com/StefH)
- [#626](https://github.com/WireMock-Net/WireMock.Net/issues/626) - version 1.4.19 throws a lot of analyzer errors related to the BaseBuilder.cs [bug]
# 1.4.19 (04 August 2021)
-- [#622](https://github.com/WireMock-Net/WireMock.Net/pull/622) - Add FluentBuilder for client models [feature] contributed by [StefH](https://github.com/StefH)
-- [#625](https://github.com/WireMock-Net/WireMock.Net/pull/625) - Add NotNullOrEmptyMatcher [feature] contributed by [StefH](https://github.com/StefH)
- [#621](https://github.com/WireMock-Net/WireMock.Net/issues/621) - Fluent API for RestClient MappingModel creation [feature]
- [#624](https://github.com/WireMock-Net/WireMock.Net/issues/624) - Post request with "BodyAsBytes" is not matched by RegexMatcher [bug]
# 1.4.18 (10 July 2021)
-- [#619](https://github.com/WireMock-Net/WireMock.Net/pull/619) - Update Handlebars.Net.Helpers.XPath to fix issue with 'xml version' contributed by [StefH](https://github.com/StefH)
- [#618](https://github.com/WireMock-Net/WireMock.Net/issues/618) - Trying to use attribute of the request object while creating response while mocking a soap service [bug]
-# 1.4.17 (07 July 2021)
-- [#617](https://github.com/WireMock-Net/WireMock.Net/pull/617) - Add support for Handlebars.Net.Helpers.Humanizer [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.4.16 (05 June 2021)
-- [#616](https://github.com/WireMock-Net/WireMock.Net/pull/616) - Upgrade Handlebars.Net.Helpers to 2.19 [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.15 (19 May 2021)
-- [#615](https://github.com/WireMock-Net/WireMock.Net/pull/615) - Add support for multiple webhooks [feature] contributed by [StefH](https://github.com/StefH)
- [#614](https://github.com/WireMock-Net/WireMock.Net/issues/614) - Is it possible to some how send multiple webhooks? [feature]
-# 1.4.14 (11 May 2021)
-- [#610](https://github.com/WireMock-Net/WireMock.Net/pull/610) - Fix some SonarCloud issues in UnitTests contributed by [StefH](https://github.com/StefH)
-- [#611](https://github.com/WireMock-Net/WireMock.Net/pull/611) - Allow to add custom service registrations when using ASP.NET Core [feature] contributed by [starkpl](https://github.com/starkpl)
-- [#612](https://github.com/WireMock-Net/WireMock.Net/pull/612) - Don't run SonarCloud tasks for PullRequests [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.4.13 (26 April 2021)
-- [#607](https://github.com/WireMock-Net/WireMock.Net/pull/607) - Bump System.Text.Encodings.Web from 4.5.0 to 4.5.1 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#609](https://github.com/WireMock-Net/WireMock.Net/pull/609) - Add possibility to use settings to generate MappingModel models with wildcard path parameters. [feature] contributed by [StefH](https://github.com/StefH)
- [#608](https://github.com/WireMock-Net/WireMock.Net/issues/608) - Import from OpenApi generates model with path parameter narrowed in range (example value=42 instead of '*') [feature]
-# 1.4.12 (22 April 2021)
-- [#605](https://github.com/WireMock-Net/WireMock.Net/pull/605) - Bump System.Net.Http from 4.3.3 to 4.3.4 in /src/WireMock.Net [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#606](https://github.com/WireMock-Net/WireMock.Net/pull/606) - Bump System.Net.Http from 4.3.3 to 4.3.4 in /examples/WireMock.Net.Service [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-
# 1.4.11 (18 April 2021)
-- [#604](https://github.com/WireMock-Net/WireMock.Net/pull/604) - Fix match logic for exact bytearray contributed by [StefH](https://github.com/StefH)
- [#601](https://github.com/WireMock-Net/WireMock.Net/issues/601) - Exact byte array request matching fails on specific byte arrays [bug]
# 1.4.10 (15 April 2021)
-- [#603](https://github.com/WireMock-Net/WireMock.Net/pull/603) - Fix callback with Headers [bug] contributed by [StefH](https://github.com/StefH)
- [#602](https://github.com/WireMock-Net/WireMock.Net/issues/602) - Header not being returned when set in WithCallback [bug]
-# 1.4.9 (31 March 2021)
-- [#600](https://github.com/WireMock-Net/WireMock.Net/pull/600) - WithProxy() should save the new mapping [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.4.8 (24 March 2021)
-- [#591](https://github.com/WireMock-Net/WireMock.Net/pull/591) - Webhook [feature] contributed by [StefH](https://github.com/StefH)
- [#589](https://github.com/WireMock-Net/WireMock.Net/issues/589) - How to send a request to a specific URL after sending response [feature]
-# 1.4.7 (21 March 2021)
-- [#594](https://github.com/WireMock-Net/WireMock.Net/pull/594) - Add possibility to the WithBody() to use IBodyData [feature] contributed by [StefH](https://github.com/StefH)
-- [#595](https://github.com/WireMock-Net/WireMock.Net/pull/595) - Use Handlebars.Net.Helpers Version="2.1.2" [feature] contributed by [StefH](https://github.com/StefH)
-- [#597](https://github.com/WireMock-Net/WireMock.Net/pull/597) - Remove 2 second delay from first response and add IPv6 address support [bug, feature] contributed by [benagain](https://github.com/benagain)
-
# 1.4.6 (26 February 2021)
-- [#587](https://github.com/WireMock-Net/WireMock.Net/pull/587) - Fix WithCallback logic when using other fluent builder statements [bug] contributed by [StefH](https://github.com/StefH)
- [#569](https://github.com/WireMock-Net/WireMock.Net/issues/569) - WithCallback circumvent the rest of the builder [bug]
-# 1.4.5 (11 February 2021)
-- [#585](https://github.com/WireMock-Net/WireMock.Net/pull/585) - Fix response date header [bug] contributed by [wolf8196](https://github.com/wolf8196)
-
# 1.4.4 (09 February 2021)
-- [#581](https://github.com/WireMock-Net/WireMock.Net/pull/581) - Use new Handlebars.Net.Helpers [feature] contributed by [StefH](https://github.com/StefH)
-- [#582](https://github.com/WireMock-Net/WireMock.Net/pull/582) - Add Xamarin UI tests [feature] contributed by [StefH](https://github.com/StefH)
- [#568](https://github.com/WireMock-Net/WireMock.Net/issues/568) - [Question] Dates in response templates [feature]
# 1.4.3 (05 February 2021)
-- [#570](https://github.com/WireMock-Net/WireMock.Net/pull/570) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.StandAlone.NETCoreApp [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#571](https://github.com/WireMock-Net/WireMock.Net/pull/571) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.Console.NETCoreApp2 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#572](https://github.com/WireMock-Net/WireMock.Net/pull/572) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.Console.NETCoreApp [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#573](https://github.com/WireMock-Net/WireMock.Net/pull/573) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.Console.Net461.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#574](https://github.com/WireMock-Net/WireMock.Net/pull/574) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.Console.Net452.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#575](https://github.com/WireMock-Net/WireMock.Net/pull/575) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.StandAlone.Net452 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#576](https://github.com/WireMock-Net/WireMock.Net/pull/576) - Bump log4net from 2.0.8 to 2.0.10 in /examples/WireMock.Net.Service [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#579](https://github.com/WireMock-Net/WireMock.Net/pull/579) - Net5 issue [bug] contributed by [StefH](https://github.com/StefH)
- [#577](https://github.com/WireMock-Net/WireMock.Net/issues/577) - WireMock.Net will not run with certain .net5 dependencies installed in the project [bug]
# 1.4.2 (24 January 2021)
-- [#566](https://github.com/WireMock-Net/WireMock.Net/pull/566) - Do not save Mappings when SaveMappingForStatusCodePattern does not match [bug] contributed by [StefH](https://github.com/StefH)
- [#565](https://github.com/WireMock-Net/WireMock.Net/issues/565) - NullReferenceException [bug]
# 1.4.1 (19 January 2021)
-- [#562](https://github.com/WireMock-Net/WireMock.Net/pull/562) - Refactor Transformer (add Scriban) [feature] contributed by [StefH](https://github.com/StefH)
- [#214](https://github.com/WireMock-Net/WireMock.Net/issues/214) - Feature: Add support for template language DotLiquid [feature]
-# 1.4.0 (12 January 2021)
-- [#548](https://github.com/WireMock-Net/WireMock.Net/pull/548) - Move CSharpCodeMatcher to a new project [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.3.10 (23 December 2020)
-- [#555](https://github.com/WireMock-Net/WireMock.Net/pull/555) - Add more tests for Proxy with Authorization [feature] contributed by [StefH](https://github.com/StefH)
-- [#561](https://github.com/WireMock-Net/WireMock.Net/pull/561) - Do not save "admin" mappings when running in Proxy - mode contributed by [StefH](https://github.com/StefH)
- [#559](https://github.com/WireMock-Net/WireMock.Net/issues/559) - WireMock Setting 'SaveMappingToFile' raising cast object to type error [bug]
# 1.3.9 (08 December 2020)
-- [#550](https://github.com/WireMock-Net/WireMock.Net/pull/550) - WithProxy(...) also use all proxy settings [bug] contributed by [StefH](https://github.com/StefH)
-- [#551](https://github.com/WireMock-Net/WireMock.Net/pull/551) - Add obsolete warning: CSharpCodeMatcher will be moved to a separate NuGet package 'WireMock.Net.Matchers.CSharpCode' [feature] contributed by [StefH](https://github.com/StefH)
- [#549](https://github.com/WireMock-Net/WireMock.Net/issues/549) - WithProxy(...) does not save the mappings to file [bug]
# 1.3.8 (03 December 2020)
-- [#539](https://github.com/WireMock-Net/WireMock.Net/pull/539) - Support for partial JSON matching contributed by [gleb-osokin](https://github.com/gleb-osokin)
-- [#542](https://github.com/WireMock-Net/WireMock.Net/pull/542) - Create dotnet-wiremock tool [feature] contributed by [StefH](https://github.com/StefH)
-- [#543](https://github.com/WireMock-Net/WireMock.Net/pull/543) - Add support for .NET 5 [feature] contributed by [StefH](https://github.com/StefH)
-- [#544](https://github.com/WireMock-Net/WireMock.Net/pull/544) - Use Java 11 in Azure Pipelines (needed for SonarCloud) [feature] contributed by [StefH](https://github.com/StefH)
-- [#545](https://github.com/WireMock-Net/WireMock.Net/pull/545) - Fix SonarCloud OpenCover (coverlet-coverage) [bug] contributed by [StefH](https://github.com/StefH)
-- [#547](https://github.com/WireMock-Net/WireMock.Net/pull/547) - Fix Proxying with SSL and NetCoreApp3.1 [bug] contributed by [StefH](https://github.com/StefH)
- [#524](https://github.com/WireMock-Net/WireMock.Net/issues/524) - Proxying with SSL Not Working in .NET Core 3.1 [bug]
# 1.3.6 (10 November 2020)
-- [#529](https://github.com/WireMock-Net/WireMock.Net/pull/529) - Add assertions for ClientIP, Url and ProxyUrl [feature] contributed by [akamud](https://github.com/akamud)
-- [#535](https://github.com/WireMock-Net/WireMock.Net/pull/535) - WithCallback should use also use enum HttpStatusCode [bug] contributed by [StefH](https://github.com/StefH)
-- [#537](https://github.com/WireMock-Net/WireMock.Net/pull/537) - Add Custom Certificate settings [feature] contributed by [StefH](https://github.com/StefH)
- [#533](https://github.com/WireMock-Net/WireMock.Net/issues/533) - Stubbed response with only callback returns unexpected status code. [bug]
- [#536](https://github.com/WireMock-Net/WireMock.Net/issues/536) - Overriding the default ssl certificate via file. [feature]
-# 1.3.5 (04 November 2020)
-- [#530](https://github.com/WireMock-Net/WireMock.Net/pull/530) - Fix dotnet-sonarscanner [bug] contributed by [StefH](https://github.com/StefH)
-- [#531](https://github.com/WireMock-Net/WireMock.Net/pull/531) - Add WithCallback-Async [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.3.4 (17 October 2020)
-- [#522](https://github.com/WireMock-Net/WireMock.Net/pull/522) - Add ContinuousIntegrationBuild property [feature] contributed by [StefH](https://github.com/StefH)
-- [#525](https://github.com/WireMock-Net/WireMock.Net/pull/525) - Handlebars.Net.Helpers Version="1.1.0" [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.3.3 (15 October 2020)
-- [#520](https://github.com/WireMock-Net/WireMock.Net/pull/520) - Make kestrel limits configurable contributed by [eduherminio](https://github.com/eduherminio)
- [#521](https://github.com/WireMock-Net/WireMock.Net/issues/521) - Make Kestrel limits configurable [feature]
# 1.3.2 (14 October 2020)
-- [#505](https://github.com/WireMock-Net/WireMock.Net/pull/505) - Fix reading JsonMatcher-mapping with object as pattern [bug] contributed by [StefH](https://github.com/StefH)
-- [#514](https://github.com/WireMock-Net/WireMock.Net/pull/514) - Update .NET Core 3.1 example contributed by [Crossbow78](https://github.com/Crossbow78)
- [#504](https://github.com/WireMock-Net/WireMock.Net/issues/504) - Loading mapping models with `JsonMatcher` is not working correctly [bug]
- [#513](https://github.com/WireMock-Net/WireMock.Net/issues/513) - Static mapping break from 1.2.17 to 1.2.18 and higher [bug]
-# 1.3.1 (30 September 2020)
-- [#509](https://github.com/WireMock-Net/WireMock.Net/pull/509) - Adding netcoreapp3.1 as a target framework [feature] contributed by [APIWT](https://github.com/APIWT)
-
# 1.3.0 (29 September 2020)
-- [#508](https://github.com/WireMock-Net/WireMock.Net/pull/508) - Fix vulnerability in NuGet dependencies contributed by [StefH](https://github.com/StefH)
- [#327](https://github.com/WireMock-Net/WireMock.Net/issues/327) - Index must be within the bounds of the List - Bug [bug]
- [#507](https://github.com/WireMock-Net/WireMock.Net/issues/507) - Fix vulnerability found in Microsoft.AspNetCore dependency [feature]
# 1.2.18 (13 August 2020)
-- [#496](https://github.com/WireMock-Net/WireMock.Net/pull/496) - Add setting to handle requests synchronously [feature] contributed by [StefH](https://github.com/StefH)
-- [#500](https://github.com/WireMock-Net/WireMock.Net/pull/500) - Add ThrowExceptionWhenMatcherFails option to all Matchers [feature] contributed by [StefH](https://github.com/StefH)
- [#478](https://github.com/WireMock-Net/WireMock.Net/issues/478) - Sometimes returns status code 0 in unit tests with xunit test fixture (flaky test) [bug]
# 1.2.17 (01 August 2020)
-- [#495](https://github.com/WireMock-Net/WireMock.Net/pull/495) - Scenario : stay on current state for a number of times contributed by [StefH](https://github.com/StefH)
- [#494](https://github.com/WireMock-Net/WireMock.Net/issues/494) - Stay in Current State for specified number of requests [feature]
# 1.2.16 (27 July 2020)
-- [#492](https://github.com/WireMock-Net/WireMock.Net/pull/492) - Mark FluentMockServer, FluentMockServerSettings, BlacklistedHeaders and BlacklistedCookies as obsolete [feature] contributed by [StefH](https://github.com/StefH)
- [#489](https://github.com/WireMock-Net/WireMock.Net/issues/489) - Change "blacklist" and "whitelist" terms [feature]
# 1.2.14 (09 July 2020)
-- [#479](https://github.com/WireMock-Net/WireMock.Net/pull/479) - An OpenApi (swagger) parser to generate MappingModel or mapping.json file [feature] contributed by [StefH](https://github.com/StefH)
-- [#482](https://github.com/WireMock-Net/WireMock.Net/pull/482) - Add PartialMatch to logging / logentries [feature] contributed by [StefH](https://github.com/StefH)
-- [#483](https://github.com/WireMock-Net/WireMock.Net/pull/483) - Bring in the WireMock.Net.FluentAssertions tests contributed by [akamud](https://github.com/akamud)
-- [#484](https://github.com/WireMock-Net/WireMock.Net/pull/484) - Refactor: extract interfaces [feature] contributed by [StefH](https://github.com/StefH)
-- [#487](https://github.com/WireMock-Net/WireMock.Net/pull/487) - Fixed MappingConverter when methods are null [bug] contributed by [StefH](https://github.com/StefH)
- [#486](https://github.com/WireMock-Net/WireMock.Net/issues/486) - Admin API fails to create a mapping with Request Body matching [bug]
# 1.2.13 (24 May 2020)
-- [#475](https://github.com/WireMock-Net/WireMock.Net/pull/475) - Fix Limits.KeepAliveTimeout & Limits.RequestHeadersTimeout [bug] contributed by [StefH](https://github.com/StefH)
- [#474](https://github.com/WireMock-Net/WireMock.Net/issues/474) - Performance issue with multiple httpclients (since version 1.2.10) [bug]
# 1.2.12 (23 May 2020)
-- [#472](https://github.com/WireMock-Net/WireMock.Net/pull/472) - Create new .sln contributed by [StefH](https://github.com/StefH)
-- [#473](https://github.com/WireMock-Net/WireMock.Net/pull/473) - Fixed Proxy when using MultipartForm with byte[] [bug] contributed by [StefH](https://github.com/StefH)
- [#468](https://github.com/WireMock-Net/WireMock.Net/issues/468) - Proxy mode: Incorrect handling of multipart requests [bug]
# 1.2.11.0 (18 May 2020)
-- [#469](https://github.com/WireMock-Net/WireMock.Net/pull/469) - Fix unhandled exception when target is unavailable [bug] contributed by [StefH](https://github.com/StefH)
- [#467](https://github.com/WireMock-Net/WireMock.Net/issues/467) - Proxy mode: Unhandled exception when target is not working [bug]
# 1.2.10 (17 May 2020)
-- [#456](https://github.com/WireMock-Net/WireMock.Net/pull/456) - Include Handlebars.Net.Helpers project [feature] contributed by [StefH](https://github.com/StefH)
-- [#457](https://github.com/WireMock-Net/WireMock.Net/pull/457) - Kestrel Options Limits [bug] contributed by [StefH](https://github.com/StefH)
- [#455](https://github.com/WireMock-Net/WireMock.Net/issues/455) - There is no option to increase body size while proxying [bug]
# 1.2.9.0 (14 May 2020)
-- [#465](https://github.com/WireMock-Net/WireMock.Net/pull/465) - Fix method ResetMappingsAsync in the RestEase-AdminApi [bug] contributed by [StefH](https://github.com/StefH)
- [#464](https://github.com/WireMock-Net/WireMock.Net/issues/464) - RestClient Admin API Metadata Base Path Duplication [bug]
-# 1.2.8.0 (04 May 2020)
-- [#463](https://github.com/WireMock-Net/WireMock.Net/pull/463) - GH161: Fix SourceLink support [bug] contributed by [gitfool](https://github.com/gitfool)
-
# 1.2.7.0 (30 April 2020)
-- [#461](https://github.com/WireMock-Net/WireMock.Net/pull/461) - Support Path in ProxyUrl contributed by [StefH](https://github.com/StefH)
- [#459](https://github.com/WireMock-Net/WireMock.Net/issues/459) - When respond with proxy requestMessage.Url is used, not AbsoluteUrl [bug]
# 1.2.6.0 (29 April 2020)
-- [#460](https://github.com/WireMock-Net/WireMock.Net/pull/460) - When using ResponseMessageTransformer : keep BodyEncoding [bug] contributed by [StefH](https://github.com/StefH)
- [#458](https://github.com/WireMock-Net/WireMock.Net/issues/458) - Response BodyAsString loses BodyData.Encoding when UseTransformer = true [bug]
# 1.2.5.0 (17 April 2020)
-- [#454](https://github.com/WireMock-Net/WireMock.Net/pull/454) - Fix port = 0 for net452 [bug] contributed by [StefH](https://github.com/StefH)
- [#453](https://github.com/WireMock-Net/WireMock.Net/issues/453) - MockServer not starting [bug]
# 1.2.4.0 (10 April 2020)
-- [#439](https://github.com/WireMock-Net/WireMock.Net/pull/439) - Add support for GZip and Deflate [feature] contributed by [StefH](https://github.com/StefH)
-- [#444](https://github.com/WireMock-Net/WireMock.Net/pull/444) - Add readme.md + license from mock4net [feature] contributed by [StefH](https://github.com/StefH)
-- [#451](https://github.com/WireMock-Net/WireMock.Net/pull/451) - Update NuGet dependencies (e.g. coverage related) to fix CI-build [feature] contributed by [StefH](https://github.com/StefH)
-- [#452](https://github.com/WireMock-Net/WireMock.Net/pull/452) - Add ValidatedNotNullAttribute (for SonarQube) [refactor] contributed by [StefH](https://github.com/StefH)
- [#426](https://github.com/WireMock-Net/WireMock.Net/issues/426) - Add support for compressed requests, such as GZIP or DEFLATE [feature]
# 1.2.3.0 (01 April 2020)
-- [#449](https://github.com/WireMock-Net/WireMock.Net/pull/449) - Netstandard21 [feature] contributed by [StefH](https://github.com/StefH)
- [#447](https://github.com/WireMock-Net/WireMock.Net/issues/447) - Add support for .NET Standard 2.1 / .NET Core 3.1 [feature]
- [#448](https://github.com/WireMock-Net/WireMock.Net/issues/448) - WireMock.Net is not compatible with Microsoft.VisualStudio.Web.CodeGeneration.Design 3.1.1 [bug]
# 1.2.2.0 (25 March 2020)
-- [#446](https://github.com/WireMock-Net/WireMock.Net/pull/446) - When port is provided: WireMockServer still takes a random port [bug] contributed by [StefH](https://github.com/StefH)
- [#445](https://github.com/WireMock-Net/WireMock.Net/issues/445) - Port where WireMockServer listens to - v1.2x [bug]
-# 1.2.1.0 (17 March 2020)
-- [#442](https://github.com/WireMock-Net/WireMock.Net/pull/442) - Fix Null body in handlebars transformation [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.2.0.0 (14 March 2020)
-- [#417](https://github.com/WireMock-Net/WireMock.Net/pull/417) - Let the .NET core/standard WebHostBuilder use a random port [bug] contributed by [StefH](https://github.com/StefH)
-- [#422](https://github.com/WireMock-Net/WireMock.Net/pull/422) - AllowOnlyDefinedHttpStatusCodeInResponse [bug] contributed by [StefH](https://github.com/StefH)
- [#379](https://github.com/WireMock-Net/WireMock.Net/issues/379) - Trusting the self signed certificate to enable SSL on dotnet core [bug]
- [#420](https://github.com/WireMock-Net/WireMock.Net/issues/420) - Updating to 1.1.6+ breaks tests because new AllowAnyHttpStatusCodeInResponse option defaults to false [bug]
# 1.1.10 (05 March 2020)
-- [#427](https://github.com/WireMock-Net/WireMock.Net/pull/427) - Add UsingOptions, UsingConnect and UsingTrace [feature] contributed by [StefH](https://github.com/StefH)
-- [#434](https://github.com/WireMock-Net/WireMock.Net/pull/434) - Option to disable JSON deserialization [feature] contributed by [sebastianmattar](https://github.com/sebastianmattar)
-- [#435](https://github.com/WireMock-Net/WireMock.Net/pull/435) - Also call HandlebarsRegistrationCallback when using WithCallback(..) [feature] contributed by [StefH](https://github.com/StefH)
- [#408](https://github.com/WireMock-Net/WireMock.Net/issues/408) - Intermittent threading errors with FindLogEntries [bug]
- [#433](https://github.com/WireMock-Net/WireMock.Net/issues/433) - HandlebarsRegistrationCallback not fired [feature]
# 1.1.9.0 (25 February 2020)
-- [#431](https://github.com/WireMock-Net/WireMock.Net/pull/431) - Fix LinqMatcher for JSON int64 [bug] contributed by [StefH](https://github.com/StefH)
- [#425](https://github.com/WireMock-Net/WireMock.Net/issues/425) - Allow 64 bit numbers in JSON [bug]
# 1.1.8.0 (22 February 2020)
-- [#419](https://github.com/WireMock-Net/WireMock.Net/pull/419) - Support multi line wild card matching [bug] contributed by [NoahLerner](https://github.com/NoahLerner)
-- [#421](https://github.com/WireMock-Net/WireMock.Net/pull/421) - Fix: do not return empty matchers array when Func has been used [bug] contributed by [StefH](https://github.com/StefH)
-- [#423](https://github.com/WireMock-Net/WireMock.Net/pull/423) - Fixes for Cookie and Header Reject on Match [bug] contributed by [StefH](https://github.com/StefH)
-- [#424](https://github.com/WireMock-Net/WireMock.Net/pull/424) - Don't return empty dictionary object for response headers in JSON mapping [feature] contributed by [StefH](https://github.com/StefH)
- [#418](https://github.com/WireMock-Net/WireMock.Net/issues/418) - Body matching fails if body has newline [bug]
# 1.1.7.0 (06 February 2020)
-- [#409](https://github.com/WireMock-Net/WireMock.Net/pull/409) - Admin Delete with mappings in body [feature] contributed by [NoahLerner](https://github.com/NoahLerner)
-- [#411](https://github.com/WireMock-Net/WireMock.Net/pull/411) - Improved relative path checking based on file existence [feature] contributed by [NoahLerner](https://github.com/NoahLerner)
-- [#413](https://github.com/WireMock-Net/WireMock.Net/pull/413) - Fix new Delete with body missing from IWireMockAdminApi interface contributed by [NoahLerner](https://github.com/NoahLerner)
-- [#414](https://github.com/WireMock-Net/WireMock.Net/pull/414) - Fix logger in StandAlone [bug] contributed by [StefH](https://github.com/StefH)
- [#412](https://github.com/WireMock-Net/WireMock.Net/issues/412) - WireMock Standalone - null reference exception since settings.Logger [bug]
-# 1.1.6.0 (27 January 2020)
-- [#407](https://github.com/WireMock-Net/WireMock.Net/pull/407) - AllowAnyHttpStatusCodeInResponse [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.1.5.0 (25 January 2020)
-- [#405](https://github.com/WireMock-Net/WireMock.Net/pull/405) - Fix logging an Exception Message (linux docker on azure) [bug] contributed by [StefH](https://github.com/StefH)
-- [#406](https://github.com/WireMock-Net/WireMock.Net/pull/406) - Fixed StatusCode = null or < 0 [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.1.3.0 (22 January 2020)
-- [#403](https://github.com/WireMock-Net/WireMock.Net/pull/403) - Fix for invalid cast exception contributed by [kashifsoofi](https://github.com/kashifsoofi)
- [#402](https://github.com/WireMock-Net/WireMock.Net/issues/402) - Invalid Cast Exception [bug]
# 1.1.2.0 (09 January 2020)
-- [#399](https://github.com/WireMock-Net/WireMock.Net/pull/399) - ResponseModel.StatusCode is deserialized as either string or long. [bug] contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
- [#400](https://github.com/WireMock-Net/WireMock.Net/issues/400) - StatusCode not built correctly when loaded from mapping file. [bug]
# 1.1.1.0 (09 January 2020)
-- [#398](https://github.com/WireMock-Net/WireMock.Net/pull/398) - Feature/xpath transformer [feature] contributed by [kashifsoofi](https://github.com/kashifsoofi)
- [#397](https://github.com/WireMock-Net/WireMock.Net/issues/397) - Question/Feature: Add support for selecting XPath in response template [feature]
-# 1.1.0.0 (27 December 2019)
-- [#363](https://github.com/WireMock-Net/WireMock.Net/pull/363) - WireMock.Net version 1.1.x contributed by [StefH](https://github.com/StefH)
-
# 1.0.43.0 (26 December 2019)
-- [#385](https://github.com/WireMock-Net/WireMock.Net/pull/385) - StatusCode as string [feature] contributed by [StefH](https://github.com/StefH)
- [#380](https://github.com/WireMock-Net/WireMock.Net/issues/380) - StatusCode is defined as integer (string is not possible) [bug]
- [#382](https://github.com/WireMock-Net/WireMock.Net/issues/382) - Return same request body [feature]
# 1.0.42.0 (15 December 2019)
-- [#391](https://github.com/WireMock-Net/WireMock.Net/pull/391) - Correctly support DateTime pattern as string in ExactMatcher [bug] contributed by [StefH](https://github.com/StefH)
- [#383](https://github.com/WireMock-Net/WireMock.Net/issues/383) - ExactMatcher does not accept ISO8601 DateTime? [bug]
# 1.0.41.0 (14 December 2019)
-- [#392](https://github.com/WireMock-Net/WireMock.Net/pull/392) - Fix array in JsonMatcher [bug] contributed by [StefH](https://github.com/StefH)
- [#390](https://github.com/WireMock-Net/WireMock.Net/issues/390) - JsonMatcher does not match a body containing an array of strings [bug]
# 1.0.40.0 (09 December 2019)
-- [#389](https://github.com/WireMock-Net/WireMock.Net/pull/389) - Fix QueryStringParser [bug] contributed by [StefH](https://github.com/StefH)
- [#387](https://github.com/WireMock-Net/WireMock.Net/issues/387) - Query string parameter value which contains %26 does not work with ExactMatcher [bug]
# 1.0.39.0 (07 December 2019)
-- [#370](https://github.com/WireMock-Net/WireMock.Net/pull/370) - Add WebProxySettings (use when proxying requests) [feature] contributed by [StefH](https://github.com/StefH)
-- [#388](https://github.com/WireMock-Net/WireMock.Net/pull/388) - Transform body as file [bug] contributed by [StefH](https://github.com/StefH)
- [#369](https://github.com/WireMock-Net/WireMock.Net/issues/369) - Question: Is there a way to provide a corporate proxy configuration? [feature]
- [#375](https://github.com/WireMock-Net/WireMock.Net/issues/375) - Proxying does not follow redirects : make this configurable [feature]
- [#386](https://github.com/WireMock-Net/WireMock.Net/issues/386) - Is transforming contents of XML file supported.? [bug]
# 1.0.38.0 (30 November 2019)
-- [#376](https://github.com/WireMock-Net/WireMock.Net/pull/376) - Support int values for states and scenario naming [feature] contributed by [NoahLerner](https://github.com/NoahLerner)
-- [#378](https://github.com/WireMock-Net/WireMock.Net/pull/378) - Set handlebars dependency for .net 4.5.1 to fixed value [bug] contributed by [StefH](https://github.com/StefH)
-- [#381](https://github.com/WireMock-Net/WireMock.Net/pull/381) - Use dotnet default development certificate for .NET Core 2.x [feature] contributed by [StefH](https://github.com/StefH)
- [#377](https://github.com/WireMock-Net/WireMock.Net/issues/377) - Unable to build against .NET 4.5.1 because of Handlebars [bug]
# 1.0.37.0 (08 November 2019)
-- [#373](https://github.com/WireMock-Net/WireMock.Net/pull/373) - Make Sonar and WhiteSource optional in the Azure pipelines build [feature] contributed by [StefH](https://github.com/StefH)
-- [#374](https://github.com/WireMock-Net/WireMock.Net/pull/374) - WatchStaticMappingsInSubdirectories [feature] contributed by [StefH](https://github.com/StefH)
- [#372](https://github.com/WireMock-Net/WireMock.Net/issues/372) - Reset in WireMock admin API not working fine. [feature]
# 1.0.36.0 (26 October 2019)
-- [#360](https://github.com/WireMock-Net/WireMock.Net/pull/360) - Add support for Faults [feature] contributed by [StefH](https://github.com/StefH)
- [#343](https://github.com/WireMock-Net/WireMock.Net/issues/343) - Feature: Please provide support for Bad responses. [feature]
-# 1.0.35.0 (25 October 2019)
-- [#367](https://github.com/WireMock-Net/WireMock.Net/pull/367) - No symbol NuGets [feature] contributed by [StefH](https://github.com/StefH)
-- [#368](https://github.com/WireMock-Net/WireMock.Net/pull/368) - Remove Obsolete annotations [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.34.0 (22 October 2019)
-- [#354](https://github.com/WireMock-Net/WireMock.Net/pull/354) - AllowBodyForAllHttpMethods [bug, feature] contributed by [StefH](https://github.com/StefH)
-- [#365](https://github.com/WireMock-Net/WireMock.Net/pull/365) - Bump Microsoft.AspNetCore.All from 2.0.8 to 2.0.9 in /examples/WireMock.Net.WebApplication [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
-- [#366](https://github.com/WireMock-Net/WireMock.Net/pull/366) - Update ObsoleteAnnotations [feature] contributed by [StefH](https://github.com/StefH)
- [#352](https://github.com/WireMock-Net/WireMock.Net/issues/352) - DELETE request drops the body [feature]
# 1.0.33.0 (12 October 2019)
-- [#311](https://github.com/WireMock-Net/WireMock.Net/pull/311) - fix jsonpath matcher [bug] contributed by [StefH](https://github.com/StefH)
-- [#324](https://github.com/WireMock-Net/WireMock.Net/pull/324) - Add CSharpCodeMatcher [feature] contributed by [StefH](https://github.com/StefH)
-- [#353](https://github.com/WireMock-Net/WireMock.Net/pull/353) - Fixed failing admin requests when content type includes a charset (based on idea from Paul Roub) [bug] contributed by [StefH](https://github.com/StefH)
-- [#355](https://github.com/WireMock-Net/WireMock.Net/pull/355) - Add Try-Catch to the event LogEntriesChanged [feature] contributed by [StefH](https://github.com/StefH)
-- [#357](https://github.com/WireMock-Net/WireMock.Net/pull/357) - Add Proxy Setting for: SaveMappingForStatusCodePattern to only save the mapping when the status code matches the pattern [feature] contributed by [StefH](https://github.com/StefH)
-- [#358](https://github.com/WireMock-Net/WireMock.Net/pull/358) - Fix JsonMatcher (parsing DateTimeOffset) contributed by [StefH](https://github.com/StefH)
- [#306](https://github.com/WireMock-Net/WireMock.Net/issues/306) - Writing to the response body is invalid for responses with status code 204 [bug]
- [#307](https://github.com/WireMock-Net/WireMock.Net/issues/307) - JsonPathMatcher always convert to JArray before matching [bug]
- [#329](https://github.com/WireMock-Net/WireMock.Net/issues/329) - Feature: Add support for CSharpCodeMatcher [feature]
@@ -904,150 +425,67 @@
- [#356](https://github.com/WireMock-Net/WireMock.Net/issues/356) - JsonMatcher not working when JSON contains a DateTimeOffset [bug]
# 1.0.32.0 (20 September 2019)
-- [#348](https://github.com/WireMock-Net/WireMock.Net/pull/348) - When posting new mapping, use DateParseHandling.None [bug] contributed by [StefH](https://github.com/StefH)
- [#347](https://github.com/WireMock-Net/WireMock.Net/issues/347) - Query string match on DateTimeOffset is not working [bug]
# 1.0.31.0 (19 September 2019)
-- [#334](https://github.com/WireMock-Net/WireMock.Net/pull/334) - Fix issues with Proxy mode and Binary Request Bodies [bug] contributed by [andi0b](https://github.com/andi0b)
-- [#338](https://github.com/WireMock-Net/WireMock.Net/pull/338) - Fix ContentType with parameters in Proxy Mode [bug] contributed by [StefH](https://github.com/StefH)
-- [#339](https://github.com/WireMock-Net/WireMock.Net/pull/339) - Fix ConcurrentObservableCollection [bug] contributed by [StefH](https://github.com/StefH)
-- [#345](https://github.com/WireMock-Net/WireMock.Net/pull/345) - Fix CompareTo in RequestMatchResult [bug] contributed by [StefH](https://github.com/StefH)
-- [#346](https://github.com/WireMock-Net/WireMock.Net/pull/346) - Fix recorded requests skipped by request logger contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
- [#337](https://github.com/WireMock-Net/WireMock.Net/issues/337) - Proxy Missing header Content-Type - tried with Recording [bug]
- [#344](https://github.com/WireMock-Net/WireMock.Net/issues/344) - Mapping adding order matters for multiple mappings? [bug]
# 1.0.29.0 (29 August 2019)
-- [#328](https://github.com/WireMock-Net/WireMock.Net/pull/328) - Fix LogRequest : Index Out Of Bounds [bug] contributed by [StefH](https://github.com/StefH)
-- [#331](https://github.com/WireMock-Net/WireMock.Net/pull/331) - Fix: Collection was modified exception [bug] contributed by [theramis](https://github.com/theramis)
-- [#333](https://github.com/WireMock-Net/WireMock.Net/pull/333) - JsonMatcher support IgnoreCase [feature] contributed by [StefH](https://github.com/StefH)
- [#332](https://github.com/WireMock-Net/WireMock.Net/issues/332) - Case sensitive true is ignored for JsonMatcher [feature]
# 1.0.28.0 (20 August 2019)
-- [#309](https://github.com/WireMock-Net/WireMock.Net/pull/309) - Fix LogEntries: collection was modified exception [bug] contributed by [StefH](https://github.com/StefH)
-- [#314](https://github.com/WireMock-Net/WireMock.Net/pull/314) - RequestLogExpirationDuration : use DateTime.UtcNow [bug] contributed by [StefH](https://github.com/StefH)
-- [#316](https://github.com/WireMock-Net/WireMock.Net/pull/316) - Handles case where parameter value contains == [feature] contributed by [lobsteropteryx](https://github.com/lobsteropteryx)
-- [#317](https://github.com/WireMock-Net/WireMock.Net/pull/317) - Make SaveMapping and SaveMappingToFile settings independent. [feature] contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
-- [#319](https://github.com/WireMock-Net/WireMock.Net/pull/319) - Add blacklist for Request Cookies. contributed by [vitaliydavydiak](https://github.com/vitaliydavydiak)
-- [#322](https://github.com/WireMock-Net/WireMock.Net/pull/322) - Fix MappingMatcher in case of an exception in LinqMatcher. [bug] contributed by [StefH](https://github.com/StefH)
-- [#323](https://github.com/WireMock-Net/WireMock.Net/pull/323) - Refactor MappingConverter & MatcherMapper [refactor] contributed by [StefH](https://github.com/StefH)
-- [#326](https://github.com/WireMock-Net/WireMock.Net/pull/326) - Fix Parsing Guid in PUT Mapping [bug] contributed by [StefH](https://github.com/StefH)
- [#252](https://github.com/WireMock-Net/WireMock.Net/issues/252) - Proxy with Transform
- [#308](https://github.com/WireMock-Net/WireMock.Net/issues/308) - __admin/requests - "Collection was modified" exception [bug]
- [#313](https://github.com/WireMock-Net/WireMock.Net/issues/313) - RequestLogExpirationDuration - bug [bug]
- [#325](https://github.com/WireMock-Net/WireMock.Net/issues/325) - Admin API: PUT Mapping, FormatException because of wrong parsing of the Query [bug]
-# 1.0.25.0 (23 July 2019)
-- [#304](https://github.com/WireMock-Net/WireMock.Net/pull/304) - Support WithBody with multiple matchers [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.24.0 (22 July 2019)
-- [#302](https://github.com/WireMock-Net/WireMock.Net/pull/302) - Fixed bug 301 by not setting BodyAsFile to null after first use [bug] contributed by [rwwilden](https://github.com/rwwilden)
- [#301](https://github.com/WireMock-Net/WireMock.Net/issues/301) - Error thrown when calling mocked endpoint second time when using file-based response body [bug]
-# 1.0.23.0 (16 July 2019)
-- [#298](https://github.com/WireMock-Net/WireMock.Net/pull/298) - MappingModels [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.22.0 (15 July 2019)
-- [#297](https://github.com/WireMock-Net/WireMock.Net/pull/297) - FixNullRef (#295) contributed by [StefH](https://github.com/StefH)
- [#295](https://github.com/WireMock-Net/WireMock.Net/issues/295) - NullRef in 1.0.21 [bug]
# 1.0.21.0 (03 July 2019)
-- [#286](https://github.com/WireMock-Net/WireMock.Net/pull/286) - Handlebars Extension [feature] contributed by [StefH](https://github.com/StefH)
-- [#293](https://github.com/WireMock-Net/WireMock.Net/pull/293) - workaround for AppContext.BaseDirectory being null on some platforms contributed by [eli-darkly](https://github.com/eli-darkly)
-- [#294](https://github.com/WireMock-Net/WireMock.Net/pull/294) - don't strip request body if we don't recognize the request method contributed by [eli-darkly](https://github.com/eli-darkly)
- [#289](https://github.com/WireMock-Net/WireMock.Net/issues/289) - Bug: When WatchStaticMappings=true throws exceptions on updating the mapping files [bug]
- [#290](https://github.com/WireMock-Net/WireMock.Net/issues/290) - Request body is dropped if verb is REPORT [bug]
- [#292](https://github.com/WireMock-Net/WireMock.Net/issues/292) - Can't start server in Xamarin Android [bug]
-# 1.0.20.0 (17 June 2019)
-- [#284](https://github.com/WireMock-Net/WireMock.Net/pull/284) - Add SaveToFile in the mapping [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.19.0 (15 June 2019)
- [#283](https://github.com/WireMock-Net/WireMock.Net/issues/283) - Support equal-sign in query [bug]
-# 1.0.18.0 (10 June 2019)
-- [#282](https://github.com/WireMock-Net/WireMock.Net/pull/282) - WireMock.Net.Standalone : Add --WireMockLogger commandline argument [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.0.17.0 (05 June 2019)
-- [#278](https://github.com/WireMock-Net/WireMock.Net/pull/278) - Add support for HandleBars File (to read a file) [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.16.0 (16 May 2019)
-- [#274](https://github.com/WireMock-Net/WireMock.Net/pull/274) - Sign Assembly [feature] contributed by [StefH](https://github.com/StefH)
- [#160](https://github.com/WireMock-Net/WireMock.Net/issues/160) - Feature: Sign 'WireMock.Net' [feature]
- [#267](https://github.com/WireMock-Net/WireMock.Net/issues/267) - Assembly does not have strong name
-# 1.0.15.0 (04 May 2019)
-- [#271](https://github.com/WireMock-Net/WireMock.Net/pull/271) - Support Dynamic response files using Handlebars templating [bug, feature] contributed by [StefH](https://github.com/StefH)
-- [#273](https://github.com/WireMock-Net/WireMock.Net/pull/273) - Dynamic response handlebars templating (2) [bug, feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.0.14.0 (20 April 2019)
-- [#269](https://github.com/WireMock-Net/WireMock.Net/pull/269) - Add JmesPath matcher [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.13.0 (11 April 2019)
-- [#266](https://github.com/WireMock-Net/WireMock.Net/pull/266) - [265] Add file upload to allow mocking of file operations contributed by [JackCreativeCrew](https://github.com/JackCreativeCrew)
- [#265](https://github.com/WireMock-Net/WireMock.Net/issues/265) - File Upload [feature]
# 1.0.12.0 (05 April 2019)
-- [#264](https://github.com/WireMock-Net/WireMock.Net/pull/264) - Proxy : also save multipart as string in mapping file contributed by [StefH](https://github.com/StefH)
- [#263](https://github.com/WireMock-Net/WireMock.Net/issues/263) - Content-Type multipart/form-data is not serialized in proxy and recording mode [bug]
-# 1.0.11.0 (30 March 2019)
-- [#261](https://github.com/WireMock-Net/WireMock.Net/pull/261) - Fix BodyAsJson transform bug in ResponseMessageTransformer contributed by [ghost](https://github.com/ghost)
-- [#262](https://github.com/WireMock-Net/WireMock.Net/pull/262) - Add ProvideResponse_WithJsonBodyAndTransform test contributed by [ghost](https://github.com/ghost)
-
-# 1.0.10.0 (27 March 2019)
-- [#260](https://github.com/WireMock-Net/WireMock.Net/pull/260) - Fix Response.Delay property serialization [bug] contributed by [StefH](https://github.com/StefH)
-
# 1.0.9.0 (25 March 2019)
-- [#256](https://github.com/WireMock-Net/WireMock.Net/pull/256) - Fixed Multi Param Match logic contributed by [StefH](https://github.com/StefH)
- [#255](https://github.com/WireMock-Net/WireMock.Net/issues/255) - ExactMatcher with array pattern not working? [bug]
# 1.0.8.0 (12 March 2019)
-- [#254](https://github.com/WireMock-Net/WireMock.Net/pull/254) - RequestMessageParamMatcher supports Ignore Case for the key [feature] contributed by [StefH](https://github.com/StefH)
- [#253](https://github.com/WireMock-Net/WireMock.Net/issues/253) - Request Path and query parameter keys are case-sensitive
# 1.0.7.0 (19 January 2019)
-- [#244](https://github.com/WireMock-Net/WireMock.Net/pull/244) - Fix BodyAsFile to also allow relative paths [feature] contributed by [StefH](https://github.com/StefH)
- [#240](https://github.com/WireMock-Net/WireMock.Net/issues/240) - How to submit mappings for multiple request, responses [feature]
- [#243](https://github.com/WireMock-Net/WireMock.Net/issues/243) - Not able to read response from file [bug]
# 1.0.6.1 (10 January 2019)
-- [#247](https://github.com/WireMock-Net/WireMock.Net/pull/247) - Issue 225 improve logging in example for wire mock as windows service contributed by [paulssn](https://github.com/paulssn)
-- [#249](https://github.com/WireMock-Net/WireMock.Net/pull/249) - Fixed "Content-Type multipart/form-data" [bug] contributed by [StefH](https://github.com/StefH)
- [#225](https://github.com/WireMock-Net/WireMock.Net/issues/225) - Feature: Improve logging in example for WireMock as Windows Service [feature]
- [#248](https://github.com/WireMock-Net/WireMock.Net/issues/248) - Content-Type multipart/form-data is not seen as byte[] anymore
-# 1.0.6 (15 December 2018)
-- [#242](https://github.com/WireMock-Net/WireMock.Net/pull/242) - Post multiple Mappings [feature] contributed by [StefH](https://github.com/StefH)
-
-# 1.0.5 (07 December 2018)
-- [#236](https://github.com/WireMock-Net/WireMock.Net/pull/236) - Add Random Regex (using Fare) [feature] contributed by [StefH](https://github.com/StefH)
-
# 1.0.4.21 (30 November 2018)
-- [#221](https://github.com/WireMock-Net/WireMock.Net/pull/221) - Update dependencies [feature] contributed by [StefH](https://github.com/StefH)
-- [#230](https://github.com/WireMock-Net/WireMock.Net/pull/230) - Add HandleBars Random functionality (#219) [feature] contributed by [StefH](https://github.com/StefH)
-- [#231](https://github.com/WireMock-Net/WireMock.Net/pull/231) - Use RandomDataGenerator.Net 1.0.3.0 contributed by [StefH](https://github.com/StefH)
-- [#232](https://github.com/WireMock-Net/WireMock.Net/pull/232) - Add SonarLint checks [feature] contributed by [StefH](https://github.com/StefH)
-- [#233](https://github.com/WireMock-Net/WireMock.Net/pull/233) - RandomDataGenerator.Net 1.0.4 [feature] contributed by [StefH](https://github.com/StefH)
-- [#235](https://github.com/WireMock-Net/WireMock.Net/pull/235) - Check aggregate exception during startup [bug] contributed by [StefH](https://github.com/StefH)
- [#219](https://github.com/WireMock-Net/WireMock.Net/issues/219) - Feature: random value helper [feature]
- [#234](https://github.com/WireMock-Net/WireMock.Net/issues/234) - Timeout Exception on VSTS Test Platform (Azure DevOps), with private build agent
# 1.0.4.20 (07 November 2018)
-- [#222](https://github.com/WireMock-Net/WireMock.Net/pull/222) - Codecov contributed by [StefH](https://github.com/StefH)
-- [#224](https://github.com/WireMock-Net/WireMock.Net/pull/224) - Fixed issue 223: Example for WireMock as Windows Service throws Exception because of WireMockConsoleLogger contributed by [paulssn](https://github.com/paulssn)
-- [#228](https://github.com/WireMock-Net/WireMock.Net/pull/228) - Fixed logic for IsRestrictedResponseHeader [bug] contributed by [StefH](https://github.com/StefH)
- [#223](https://github.com/WireMock-Net/WireMock.Net/issues/223) - Bug: Example for WireMock as Windows Service throws Exception because of WireMockConsoleLogger [bug]
-# 1.0.4.19 (31 October 2018)
-- [#220](https://github.com/WireMock-Net/WireMock.Net/pull/220) - Update SimpleCommandLineParser to handle arguments with key and value contributed by [StefH](https://github.com/StefH)
-
# 1.0.4.18 (27 October 2018)
-- [#207](https://github.com/WireMock-Net/WireMock.Net/pull/207) - Rewrite some unit-integration-tests to unit-tests (#206) contributed by [StefH](https://github.com/StefH)
-- [#208](https://github.com/WireMock-Net/WireMock.Net/pull/208) - Refactor contributed by [StefH](https://github.com/StefH)
-- [#209](https://github.com/WireMock-Net/WireMock.Net/pull/209) - NET Core 2.1 + support for Service Fabric commandline parameters contributed by [StefH](https://github.com/StefH)
-- [#212](https://github.com/WireMock-Net/WireMock.Net/pull/212) - Update BodyParser logic contributed by [StefH](https://github.com/StefH)
-- [#217](https://github.com/WireMock-Net/WireMock.Net/pull/217) - Enable Source Link contributed by [kashifsoofi](https://github.com/kashifsoofi)
-- [#218](https://github.com/WireMock-Net/WireMock.Net/pull/218) - remove appveyor contributed by [StefH](https://github.com/StefH)
- [#107](https://github.com/WireMock-Net/WireMock.Net/issues/107) - Feature: increase code coverage [feature]
- [#161](https://github.com/WireMock-Net/WireMock.Net/issues/161) - Feature: Implement SourceLink [feature]
- [#179](https://github.com/WireMock-Net/WireMock.Net/issues/179) - BodyAsFile .json files interferes with WatchStaticMappings
@@ -1059,43 +497,31 @@
- [#215](https://github.com/WireMock-Net/WireMock.Net/issues/215) - Issue: upgrade Microsoft.AspNetCore / Microsoft.AspNetCore.All to 2.1.5
# 1.0.4.17 (22 September 2018)
-- [#203](https://github.com/WireMock-Net/WireMock.Net/pull/203) - Set up CI with Azure Pipelines contributed by [azure-pipelines[bot]](https://github.com/apps/azure-pipelines)
-- [#204](https://github.com/WireMock-Net/WireMock.Net/pull/204) - Lower priority from Proxy mappings in favor of Admin Mappings [feature] contributed by [StefH](https://github.com/StefH)
- [#200](https://github.com/WireMock-Net/WireMock.Net/issues/200) - Issue: Incorrect port matching
- [#205](https://github.com/WireMock-Net/WireMock.Net/issues/205) - Issue: DELETE method is proxied as lowercase [bug]
# 1.0.4.16 (11 September 2018)
-- [#202](https://github.com/WireMock-Net/WireMock.Net/pull/202) - Update handlebars code to support Regex.Match (#201) contributed by [StefH](https://github.com/StefH)
- [#201](https://github.com/WireMock-Net/WireMock.Net/issues/201) - Question : Extracting text from a request.body that is not json
# 1.0.4.15 (04 September 2018)
-- [#199](https://github.com/WireMock-Net/WireMock.Net/pull/199) - Fix for .WithBody(Func<RequestMessage, string>...) contributed by [StefH](https://github.com/StefH)
- [#198](https://github.com/WireMock-Net/WireMock.Net/issues/198) - Issue : creating response using .WithBody(Func<RequestMessage, string>...) and .WithStatusCode [bug]
# 1.0.4.14 (02 September 2018)
-- [#197](https://github.com/WireMock-Net/WireMock.Net/pull/197) - Set IsStarted = true in a IApplicationLifetime.ApplicationStarted listener [bug] contributed by [davide-romanini](https://github.com/davide-romanini)
- [#196](https://github.com/WireMock-Net/WireMock.Net/issues/196) - Issue: AspNetCoreSelfHost.IsStarted set before the server actually started for real [bug]
# 1.0.4.13 (31 August 2018)
-- [#195](https://github.com/WireMock-Net/WireMock.Net/pull/195) - Add LinqMatcher contributed by [StefH](https://github.com/StefH)
- [#192](https://github.com/WireMock-Net/WireMock.Net/issues/192) - Cannot upgrade from 1.0.4.10 to 1.0.4.12 without upgrading to .net core 2.1 [bug]
# 1.0.4.12 (23 August 2018)
-- [#190](https://github.com/WireMock-Net/WireMock.Net/pull/190) - Fix ResponseMessageTransformer (#188) contributed by [StefH](https://github.com/StefH)
-- [#191](https://github.com/WireMock-Net/WireMock.Net/pull/191) - Fix ignore case logic for header-name and cookie-name contributed by [StefH](https://github.com/StefH)
- [#188](https://github.com/WireMock-Net/WireMock.Net/issues/188) - Bug: ResponseMessageTransformer :
- [#189](https://github.com/WireMock-Net/WireMock.Net/issues/189) - Issue: Case of header key/name not ignored in RequestBuilder when ignoreCase == true
# 1.0.4.11 (20 August 2018)
-- [#183](https://github.com/WireMock-Net/WireMock.Net/pull/183) - Set Content-Type header for PutMappingAsync in the client contributed by [seanamosw](https://github.com/seanamosw)
-- [#185](https://github.com/WireMock-Net/WireMock.Net/pull/185) - Support Microsoft.AspNetCore for net 4.6.1 and up [feature] contributed by [StefH](https://github.com/StefH)
-- [#186](https://github.com/WireMock-Net/WireMock.Net/pull/186) - ContentType "application/vnd.api+json" is not recognized as json contributed by [steveland83](https://github.com/steveland83)
- [#182](https://github.com/WireMock-Net/WireMock.Net/issues/182) - Bug: IFluentMockServerAdmin::PutMappingAsync does not set Content-Type
- [#184](https://github.com/WireMock-Net/WireMock.Net/issues/184) - Bug: Fix AppVeyor PR build process
- [#187](https://github.com/WireMock-Net/WireMock.Net/issues/187) - Bug: Admin GetRequestAsync does not populate request body for JsonApi ("application/vnd.api+json") content
# 1.0.4.10 (14 August 2018)
-- [#180](https://github.com/WireMock-Net/WireMock.Net/pull/180) - Add IFileSystemHandler to support Azure for StaticMapping location contributed by [StefH](https://github.com/StefH)
- [#173](https://github.com/WireMock-Net/WireMock.Net/issues/173) - Feature: Mapping files lost when restarting an Azure app service [feature]
# 1.0.4.9 (08 August 2018)
@@ -1106,21 +532,15 @@
- [#177](https://github.com/WireMock-Net/WireMock.Net/issues/177) - Feature: Skip invalid static mapping files [feature]
# 1.0.4.8 (23 July 2018)
-- [#170](https://github.com/WireMock-Net/WireMock.Net/pull/170) - Support json path in the response contributed by [StefH](https://github.com/StefH)
- [#167](https://github.com/WireMock-Net/WireMock.Net/issues/167) - Feature: Support for JsonPath in the response (with HandleBars) [feature]
# 1.0.4.7 (19 July 2018)
-- [#169](https://github.com/WireMock-Net/WireMock.Net/pull/169) - Fix for Restricted Response headers [bug] contributed by [StefH](https://github.com/StefH)
- [#148](https://github.com/WireMock-Net/WireMock.Net/issues/148) - Question: proxy passthrough when no match?
# 1.0.4.6 (18 July 2018)
-- [#168](https://github.com/WireMock-Net/WireMock.Net/pull/168) - Expose scenario states [feature] contributed by [StefH](https://github.com/StefH)
- [#163](https://github.com/WireMock-Net/WireMock.Net/issues/163) - Feature: Expose scenario states
# 1.0.4.5 (17 July 2018)
-- [#164](https://github.com/WireMock-Net/WireMock.Net/pull/164) - Support running WireMock.Net as a sub-app in IIS [feature] contributed by [StefH](https://github.com/StefH)
-- [#165](https://github.com/WireMock-Net/WireMock.Net/pull/165) - Add SonarCloud contributed by [StefH](https://github.com/StefH)
-- [#166](https://github.com/WireMock-Net/WireMock.Net/pull/166) - Fix Sonar issues contributed by [StefH](https://github.com/StefH)
- [#120](https://github.com/WireMock-Net/WireMock.Net/issues/120) - Question: JsonPathMatcher - not matching? Correct syntax?
- [#123](https://github.com/WireMock-Net/WireMock.Net/issues/123) - Fix for DateTime Header causing null value in ResponseBuilder
@@ -1131,7 +551,6 @@
- [#159](https://github.com/WireMock-Net/WireMock.Net/issues/159) - Bug: IRequestBuilder.WithParam broken for key-only matching [bug]
# 1.0.4.2 (26 June 2018)
-- [#157](https://github.com/WireMock-Net/WireMock.Net/pull/157) - Support for string and object in JsonMatcher. [feature] contributed by [StefH](https://github.com/StefH)
- [#150](https://github.com/WireMock-Net/WireMock.Net/issues/150) - Add support for .NET Core 2.1 (.NET Core 2.0 will reach end of life on september 2018)
- [#154](https://github.com/WireMock-Net/WireMock.Net/issues/154) - Feature: support BodyAsJson for Request in static mapping files. [feature]
@@ -1144,16 +563,10 @@
- [#151](https://github.com/WireMock-Net/WireMock.Net/issues/151) - Feature: Add logging of incoming request and body for tracability
# 1.0.3.20 (29 May 2018)
-- [#147](https://github.com/WireMock-Net/WireMock.Net/pull/147) - Revert PortUtil.cs changes contributed by [StefH](https://github.com/StefH)
- [#129](https://github.com/WireMock-Net/WireMock.Net/issues/129) - Random test failures between WireMock.Net 1.0.3.1 and 1.0.3.2
- [#146](https://github.com/WireMock-Net/WireMock.Net/issues/146) - Hang possibly due to Windows firewall prompt
-# 1.0.3.19 (28 May 2018)
-- [#144](https://github.com/WireMock-Net/WireMock.Net/pull/144) - Fix ConcurrentDictionary (#129) contributed by [StefH](https://github.com/StefH)
-- [#145](https://github.com/WireMock-Net/WireMock.Net/pull/145) - Cancellation token not passed to server instance in .NET Core 2 [bug] contributed by [Bob11327](https://github.com/Bob11327)
-
# 1.0.3.18 (25 May 2018)
-- [#142](https://github.com/WireMock-Net/WireMock.Net/pull/142) - Allow all headers to be set as Response headers contributed by [StefH](https://github.com/StefH)
- [#122](https://github.com/WireMock-Net/WireMock.Net/issues/122) - WireMock.Net not responding in unit tests - same works in console application
- [#126](https://github.com/WireMock-Net/WireMock.Net/issues/126) - Question: UsingHead always returns 0 for Content-Length header even when explicitly specified
- [#132](https://github.com/WireMock-Net/WireMock.Net/issues/132) - LogEntries not being recorded on subsequent tests
@@ -1162,19 +575,12 @@
- [#139](https://github.com/WireMock-Net/WireMock.Net/issues/139) - Wiki link https://github.com/StefH/WireMock.Net/wiki/Record-(via-proxy)-and-Save is dead
# 1.0.3.17 (16 May 2018)
-- [#134](https://github.com/WireMock-Net/WireMock.Net/pull/134) - Stef negate matcher contributed by [alastairtree](https://github.com/alastairtree)
-- [#138](https://github.com/WireMock-Net/WireMock.Net/pull/138) - Added Negate matcher logic contributed by [StefH](https://github.com/StefH)
- [#130](https://github.com/WireMock-Net/WireMock.Net/issues/130) - ...
# 1.0.3.16 (17 April 2018)
-- [#121](https://github.com/WireMock-Net/WireMock.Net/pull/121) - Fix for issue #118 [bug] contributed by [raghavendrabankapur](https://github.com/raghavendrabankapur)
-- [#125](https://github.com/WireMock-Net/WireMock.Net/pull/125) - Change listen from loopback to any ip address for dotnetcore2.0 apps contributed by [SubjectiveReality](https://github.com/SubjectiveReality)
- [#118](https://github.com/WireMock-Net/WireMock.Net/issues/118) - Not reading the response from a file when mappings are placed in json file
- [#124](https://github.com/WireMock-Net/WireMock.Net/issues/124) - Issue: Unable to get host to listen on ips other than 127.0.0.1 using StandAloneApp
-# 1.0.3.15 (05 April 2018)
-- [#117](https://github.com/WireMock-Net/WireMock.Net/pull/117) - Respect start timeout setting and expose exception from server startup contributed by [evanlwj](https://github.com/evanlwj)
-
# 1.0.3.14 (01 April 2018)
- [#111](https://github.com/WireMock-Net/WireMock.Net/issues/111) - Question: Adding wiki documentation on how to use WireMock.Net.WebApplication project
- [#112](https://github.com/WireMock-Net/WireMock.Net/issues/112) - Question: Request.Create().WithBody() not able to match with custom class which implements IMatcher
@@ -1194,25 +600,18 @@
- [#106](https://github.com/WireMock-Net/WireMock.Net/issues/106) - Issue: Params does not work, when there are multiple values for a key
# 1.0.3.4 (04 March 2018)
-- [#95](https://github.com/WireMock-Net/WireMock.Net/pull/95) - Unittest fix contributed by [StefH](https://github.com/StefH)
-- [#96](https://github.com/WireMock-Net/WireMock.Net/pull/96) - Replace log4net by custom logger (#94) contributed by [StefH](https://github.com/StefH)
-- [#101](https://github.com/WireMock-Net/WireMock.Net/pull/101) - ICallbackResponseBuilder + added more unit-tests [bug] contributed by [StefH](https://github.com/StefH)
-- [#102](https://github.com/WireMock-Net/WireMock.Net/pull/102) - Feature: add WithBody(req => dostuff) style callback [feature] contributed by [alastairtree](https://github.com/alastairtree)
- [#66](https://github.com/WireMock-Net/WireMock.Net/issues/66) - Interested in callbacks?
- [#93](https://github.com/WireMock-Net/WireMock.Net/issues/93) - Bug: FluentMockServer IsStarted after calling Start()
- [#94](https://github.com/WireMock-Net/WireMock.Net/issues/94) - Issue: Introduced dependency on log4net
- [#98](https://github.com/WireMock-Net/WireMock.Net/issues/98) - IBodyResponseBuilder.WithBody* should receive the request as a parameter
# 1.0.3.3 (24 February 2018)
-- [#92](https://github.com/WireMock-Net/WireMock.Net/pull/92) - Json fixes (#91) contributed by [StefH](https://github.com/StefH)
- [#91](https://github.com/WireMock-Net/WireMock.Net/issues/91) - Bug: WireMock.Net is not matching application/json http requests using JSONPathMatcher [bug]
# 1.0.3.2 (14 February 2018)
-- [#90](https://github.com/WireMock-Net/WireMock.Net/pull/90) - Concurrent issue (#88) contributed by [StefH](https://github.com/StefH)
- [#88](https://github.com/WireMock-Net/WireMock.Net/issues/88) - Bug: Standalone server throws 500 error when receiving concurrent requests [bug]
# 1.0.3.1 (14 February 2018)
-- [#89](https://github.com/WireMock-Net/WireMock.Net/pull/89) - Add log4net logging contributed by [StefH](https://github.com/StefH)
- [#87](https://github.com/WireMock-Net/WireMock.Net/issues/87) - Feature: Add logging
# 1.0.3.0 (05 February 2018)
@@ -1224,13 +623,10 @@
- [#86](https://github.com/WireMock-Net/WireMock.Net/issues/86) - Feature : Add FileSystemWatcher logic for watching static mapping files [feature]
# 1.0.2.13 (23 January 2018)
-- [#79](https://github.com/WireMock-Net/WireMock.Net/pull/79) - Fix missed content headers contributed by [volodymyr-fed](https://github.com/volodymyr-fed)
- [#57](https://github.com/WireMock-Net/WireMock.Net/issues/57) - ProxyAndRecord does not save query-parameters, headers and body [bug]
- [#78](https://github.com/WireMock-Net/WireMock.Net/issues/78) - WireMock not working when attempting to access from anything other than localhost.
# 1.0.2.12 (16 January 2018)
-- [#75](https://github.com/WireMock-Net/WireMock.Net/pull/75) - Add WireMock.Net.WebApplication example contributed by [StefH](https://github.com/StefH)
-- [#77](https://github.com/WireMock-Net/WireMock.Net/pull/77) - Fixed issue #76 contributed by [StefH](https://github.com/StefH)
- [#73](https://github.com/WireMock-Net/WireMock.Net/issues/73) - Updated mapping is not being picked and responded with the response
- [#76](https://github.com/WireMock-Net/WireMock.Net/issues/76) - Bug: IFluentMockServerAdmin is missing content-type for some POST/PUT calls
@@ -1241,42 +637,27 @@
- [#70](https://github.com/WireMock-Net/WireMock.Net/issues/70) - Proxy/Intercept pattern is throwing a keep alive header error with net461
# 1.0.2.9 (07 December 2017)
-- [#71](https://github.com/WireMock-Net/WireMock.Net/pull/71) - Fixed restricted headers on response contributed by [StefH](https://github.com/StefH)
- [#69](https://github.com/WireMock-Net/WireMock.Net/issues/69) - Instructions are incorrect (?)
# 1.0.2.8 (23 November 2017)
-- [#65](https://github.com/WireMock-Net/WireMock.Net/pull/65) - bug: Fix admin api client definition returning the wrong types contributed by [alastairtree](https://github.com/alastairtree)
-- [#67](https://github.com/WireMock-Net/WireMock.Net/pull/67) - bug: fix supporting the Patch method and logging the body contributed by [alastairtree](https://github.com/alastairtree)
- [#64](https://github.com/WireMock-Net/WireMock.Net/issues/64) - Pull Requests do not trigger test + codecoverage ?
# 1.0.2.7 (18 November 2017)
-- [#62](https://github.com/WireMock-Net/WireMock.Net/pull/62) - Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating contributed by [alastairtree](https://github.com/alastairtree)
-- [#63](https://github.com/WireMock-Net/WireMock.Net/pull/63) - Fix issue with concurrent logging contributed by [volodymyr-fed](https://github.com/volodymyr-fed)
- [#27](https://github.com/WireMock-Net/WireMock.Net/issues/27) - New feature: Record and Save
- [#42](https://github.com/WireMock-Net/WireMock.Net/issues/42) - Enhancement - Save/load request logs to/from disk [feature]
- [#53](https://github.com/WireMock-Net/WireMock.Net/issues/53) - New feature request: Access to Owin pipeline
# 1.0.2.6 (30 October 2017)
-- [#59](https://github.com/WireMock-Net/WireMock.Net/pull/59) - Add ability to provide multiple values for headers in response contributed by [Dreamescaper](https://github.com/Dreamescaper)
-- [#60](https://github.com/WireMock-Net/WireMock.Net/pull/60) - Fix proxy headers handling contributed by [Dreamescaper](https://github.com/Dreamescaper)
- [#54](https://github.com/WireMock-Net/WireMock.Net/issues/54) - Proxy for AWS: Error unmarshalling response back from AWS [bug]
- [#56](https://github.com/WireMock-Net/WireMock.Net/issues/56) - WithBodyFromFile Support [feature]
- [#58](https://github.com/WireMock-Net/WireMock.Net/issues/58) - Multiple headers with same name [feature]
# 1.0.2.5 (24 October 2017)
-- [#55](https://github.com/WireMock-Net/WireMock.Net/pull/55) - Fix the problem with headers passthrough [bug] contributed by [dmtrrk](https://github.com/dmtrrk)
- [#44](https://github.com/WireMock-Net/WireMock.Net/issues/44) - Bug: Server not listening after Start() returns (on macOS) [bug]
- [#48](https://github.com/WireMock-Net/WireMock.Net/issues/48) - Stateful support [feature]
- [#52](https://github.com/WireMock-Net/WireMock.Net/issues/52) - SimMetrics.NET error when trying to install NuGet Package
# 1.0.2.4 (10 October 2017)
-- [#32](https://github.com/WireMock-Net/WireMock.Net/pull/32) - [Feature] Add support for client certificate password and test with real services that require client certificate auth [feature] contributed by [phillee007](https://github.com/phillee007)
-- [#35](https://github.com/WireMock-Net/WireMock.Net/pull/35) - Revert changes that were made by mistake in prior PR contributed by [phillee007](https://github.com/phillee007)
-- [#39](https://github.com/WireMock-Net/WireMock.Net/pull/39) - Listen on http://*:9090 contributed by [StefH](https://github.com/StefH)
-- [#40](https://github.com/WireMock-Net/WireMock.Net/pull/40) - Expose more settings to stand-alone app contributed by [StefH](https://github.com/StefH)
-- [#41](https://github.com/WireMock-Net/WireMock.Net/pull/41) - Dotnet 20 preview final [feature] contributed by [StefH](https://github.com/StefH)
-- [#45](https://github.com/WireMock-Net/WireMock.Net/pull/45) - Add RequestLogExpirationDuration and MaxRequestLogCount (#43) contributed by [StefH](https://github.com/StefH)
-- [#51](https://github.com/WireMock-Net/WireMock.Net/pull/51) - Observable logs contributed by [dmtrrk](https://github.com/dmtrrk)
- [#15](https://github.com/WireMock-Net/WireMock.Net/issues/15) - New feature: Proxying [feature]
- [#20](https://github.com/WireMock-Net/WireMock.Net/issues/20) - Add client certificate authentication [feature]
- [#31](https://github.com/WireMock-Net/WireMock.Net/issues/31) - Feature request: Nuget package for standalone version [feature]
@@ -1291,13 +672,11 @@
- [#30](https://github.com/WireMock-Net/WireMock.Net/issues/30) - [Feature] Disable partial mappings by default in standalone version [bug, feature]
# 1.0.2.0 (05 May 2017)
-- [#26](https://github.com/WireMock-Net/WireMock.Net/pull/26) - merge netstandard into main contributed by [StefH](https://github.com/StefH)
- [#21](https://github.com/WireMock-Net/WireMock.Net/issues/21) - Admin static json mappings [feature]
- [#23](https://github.com/WireMock-Net/WireMock.Net/issues/23) - Consider port to .Net Core
- [#25](https://github.com/WireMock-Net/WireMock.Net/issues/25) - Upgrade to vs2017 [feature]
# 1.0.1.2 (27 February 2017)
-- [#24](https://github.com/WireMock-Net/WireMock.Net/pull/24) - Body Encoding contributed by [sbebrys](https://github.com/sbebrys)
- [#8](https://github.com/WireMock-Net/WireMock.Net/issues/8) - admin rest api
- [#22](https://github.com/WireMock-Net/WireMock.Net/issues/22) - Add basic-authentication for accessing admin-interface [feature]
diff --git a/Directory.Build.props b/Directory.Build.props
index 1fb52791..b171c96a 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -4,7 +4,7 @@
- 1.8.0-prview-01
+ 1.7.5-preview-02
WireMock.Net-Logo.png
https://github.com/WireMock-Net/WireMock.Net
Apache-2.0
diff --git a/Generate-ReleaseNotes.cmd b/Generate-ReleaseNotes.cmd
index 2d1a3761..998b0d48 100644
--- a/Generate-ReleaseNotes.cmd
+++ b/Generate-ReleaseNotes.cmd
@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
-SET version=1.8.0-prview-01
+SET version=1.7.5-preview-02
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
diff --git a/PackageReleaseNotes.txt b/PackageReleaseNotes.txt
index a6878fbb..7893c0bf 100644
--- a/PackageReleaseNotes.txt
+++ b/PackageReleaseNotes.txt
@@ -1,5 +1,6 @@
-# 1.7.4 (27 February 2025)
-- #1256 Add ToArray() to ConcurrentObservableCollection [bug]
-- #1254 FindLogEntries exception 'Destination array was not long enough' [bug]
+# 1.7.5-preview-02 (03 April 2025)
+- #1265 Fix construction of path in OpenApiParser [bug]
+- #1269 Server-Sent Events [feature]
+- #1264 OpenApiParser - Construction of path possibly incorrect [bug]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
\ No newline at end of file
diff --git a/WireMock.Net Solution.sln.DotSettings b/WireMock.Net Solution.sln.DotSettings
index 8d0a52ef..4e64aaeb 100644
--- a/WireMock.Net Solution.sln.DotSettings
+++ b/WireMock.Net Solution.sln.DotSettings
@@ -35,6 +35,7 @@
True
True
True
+ True
True
True
True
diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
index 6bc1fd47..13046fd9 100644
--- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
+++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
@@ -97,6 +97,46 @@ message HelloReply {
fullName:String
}";
+ private static void RunSse()
+ {
+ var server = WireMockServer.Start(new WireMockServerSettings
+ {
+ Port = 9091,
+ StartAdminInterface = true,
+ Logger = new WireMockConsoleLogger()
+ });
+ server
+ .WhenRequest(r => r
+ .UsingGet()
+ .WithPath("/sse")
+ )
+ .ThenRespondWith(r => r
+ .WithHeader("Content-Type", "text/event-stream")
+ .WithHeader("Cache-Control", "no-cache")
+ .WithHeader("Connection", "keep-alive")
+ .WithSseBody(async (_, q) =>
+ {
+ for (var i = 0; i < 5; i++)
+ {
+ q.Write("test " + i + "\r\n");
+ await Task.Delay(5000);
+ }
+
+ q.Close();
+ })
+ );
+
+ server
+ .WhenRequest(r => r
+ .UsingGet()
+ )
+ .ThenRespondWith(r => r
+ .WithBody("normal")
+ );
+
+ System.Console.ReadKey();
+ }
+
private static void RunOnLocal()
{
try
@@ -136,6 +176,7 @@ message HelloReply {
public static void Run()
{
+ RunSse();
RunOnLocal();
var mappingBuilder = new MappingBuilder();
diff --git a/src/WireMock.Net.Abstractions/Models/IBlockingQueue.cs b/src/WireMock.Net.Abstractions/Models/IBlockingQueue.cs
new file mode 100644
index 00000000..054dfa1a
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/Models/IBlockingQueue.cs
@@ -0,0 +1,30 @@
+// Copyright © WireMock.Net
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace WireMock.Models;
+
+///
+/// A simple implementation for a Blocking Queue.
+///
+/// Specifies the type of elements in the queue.
+public interface IBlockingQueue
+{
+ ///
+ /// Writes an item to the queue and signals that an item is available.
+ ///
+ /// The item to be added to the queue.
+ void Write(T item);
+
+ ///
+ /// Tries to read an item from the queue. Waits until an item is available or the timeout occurs.
+ ///
+ /// The item read from the queue, or default if the timeout occurs.
+ /// True if an item was successfully read; otherwise, false.
+ bool TryRead([NotNullWhen(true)] out T? item);
+
+ ///
+ /// Closes the queue and signals all waiting threads.
+ ///
+ public void Close();
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Models/IBodyData.cs b/src/WireMock.Net.Abstractions/Models/IBodyData.cs
index 7c9f35e6..79b737d5 100644
--- a/src/WireMock.Net.Abstractions/Models/IBodyData.cs
+++ b/src/WireMock.Net.Abstractions/Models/IBodyData.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
using WireMock.Models;
using WireMock.Types;
@@ -71,7 +72,7 @@ public interface IBodyData
Encoding? Encoding { get; set; }
///
- /// Defines if this BodyData is the result of a dynamically created response-string. (
+ /// Defines if this BodyData is the result of a dynamically created response-string.
///
public string? IsFuncUsed { get; set; }
@@ -86,4 +87,14 @@ public interface IBodyData
///
public string? ProtoBufMessageType { get; set; }
#endregion
+
+ ///
+ /// Defines the queue to use for Server-Sent Events (string).
+ ///
+ public IBlockingQueue? SseStringQueue { get; set; }
+
+ ///
+ /// Defines if the body is using Server-Sent Events (string).
+ ///
+ public Task? BodyAsSseStringTask { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Types/BodyType.cs b/src/WireMock.Net.Abstractions/Types/BodyType.cs
index 38c14a9d..6894c369 100644
--- a/src/WireMock.Net.Abstractions/Types/BodyType.cs
+++ b/src/WireMock.Net.Abstractions/Types/BodyType.cs
@@ -45,5 +45,10 @@ public enum BodyType
///
/// Body is a ProtoBuf Byte array
///
- ProtoBuf
+ ProtoBuf,
+
+ ///
+ /// Use Server-Sent Events (string)
+ ///
+ SseString
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/WireMock.Net.Abstractions.csproj b/src/WireMock.Net.Abstractions/WireMock.Net.Abstractions.csproj
index 85cf222e..4b010184 100644
--- a/src/WireMock.Net.Abstractions/WireMock.Net.Abstractions.csproj
+++ b/src/WireMock.Net.Abstractions/WireMock.Net.Abstractions.csproj
@@ -61,4 +61,11 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
index 8034318e..a819a1f9 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
@@ -1,6 +1,6 @@
// Copyright © WireMock.Net
-#if NET46 || NETSTANDARD2_0
+#if NET46 || NET47 || NETSTANDARD2_0
using System.Collections.Generic;
namespace WireMock.Net.OpenApiParser.Extensions;
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
index efd4bfcd..02f7a49b 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
@@ -1,60 +1,53 @@
// Copyright © WireMock.Net
using System.Linq;
+using System.Text.Json;
using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using WireMock.Net.OpenApiParser.Types;
namespace WireMock.Net.OpenApiParser.Extensions;
internal static class OpenApiSchemaExtensions
{
- ///
- /// https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger
- ///
- public static bool TryGetXNullable(this OpenApiSchema schema, out bool value)
+ public static bool TryGetXNullable(this IOpenApiSchema schema, out bool value)
{
value = false;
- if (schema.Extensions.TryGetValue("x-nullable", out var e) && e is OpenApiBoolean openApiBoolean)
+ if (schema.Extensions != null && schema.Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: { } jsonNode })
{
- value = openApiBoolean.Value;
+ value = jsonNode.GetValueKind() == JsonValueKind.True;
return true;
}
return false;
}
- public static SchemaType GetSchemaType(this OpenApiSchema? schema)
+ public static JsonSchemaType? GetSchemaType(this IOpenApiSchema? schema, out bool isNullable)
{
+ isNullable = false;
+
if (schema == null)
{
- return SchemaType.Unknown;
+ return null;
}
if (schema.Type == null)
{
- if (schema.AllOf.Any() || schema.AnyOf.Any())
+ if (schema.AllOf?.Any() == true || schema.AnyOf?.Any() == true)
{
- return SchemaType.Object;
+ return JsonSchemaType.Object;
}
}
- return schema.Type switch
- {
- "object" => SchemaType.Object,
- "array" => SchemaType.Array,
- "integer" => SchemaType.Integer,
- "number" => SchemaType.Number,
- "boolean" => SchemaType.Boolean,
- "string" => SchemaType.String,
- "file" => SchemaType.File,
- _ => SchemaType.Unknown
- };
+ isNullable = (schema.Type | JsonSchemaType.Null) == JsonSchemaType.Null || (schema.TryGetXNullable(out var xNullable) && xNullable);
+
+ // Removes the Null flag from the schema.Type, ensuring the returned value represents a non-nullable type.
+ return schema.Type & ~JsonSchemaType.Null;
}
- public static SchemaFormat GetSchemaFormat(this OpenApiSchema? schema)
+ public static SchemaFormat GetSchemaFormat(this IOpenApiSchema? schema)
{
switch (schema?.Format)
{
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
index b2aadb06..bd20f521 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
@@ -4,7 +4,7 @@ using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers;
+using Microsoft.OpenApi.Reader;
using Stef.Validation;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Server;
@@ -17,7 +17,7 @@ namespace WireMock.Net.OpenApiParser.Extensions;
public static class WireMockServerExtensions
{
///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
+ /// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
///
/// The WireMockServer instance
/// Path containing OpenAPI file to parse and use the mappings.
@@ -29,7 +29,7 @@ public static class WireMockServerExtensions
}
///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
+ /// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
///
/// The WireMockServer instance
/// Path containing OpenAPI file to parse and use the mappings.
@@ -47,7 +47,7 @@ public static class WireMockServerExtensions
}
///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
+ /// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
///
/// The WireMockServer instance
/// Stream containing OpenAPI description to parse and use the mappings.
@@ -59,7 +59,7 @@ public static class WireMockServerExtensions
}
///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
+ /// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
///
/// The WireMockServer instance
/// Stream containing OpenAPI description to parse and use the mappings.
@@ -78,7 +78,7 @@ public static class WireMockServerExtensions
}
///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
+ /// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 document.
///
/// The WireMockServer instance
/// The OpenAPI document to use as mappings.
diff --git a/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs b/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
index e54ded9f..4118414c 100644
--- a/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
+++ b/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
@@ -3,7 +3,7 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers;
+using Microsoft.OpenApi.Reader;
using WireMock.Admin.Mappings;
using WireMock.Net.OpenApiParser.Settings;
@@ -17,7 +17,7 @@ public interface IWireMockOpenApiParser
///
/// Generate from a file-path.
///
- /// The path to read the OpenApi/Swagger/V2/V3 or Raml file.
+ /// The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.
/// OpenApiDiagnostic output
/// MappingModel
IReadOnlyList FromFile(string path, out OpenApiDiagnostic diagnostic);
@@ -25,7 +25,7 @@ public interface IWireMockOpenApiParser
///
/// Generate from a file-path.
///
- /// The path to read the OpenApi/Swagger/V2/V3 or Raml file.
+ /// The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.
/// Additional settings
/// OpenApiDiagnostic output
/// MappingModel
diff --git a/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs b/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
index a4167db7..e48766e0 100644
--- a/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
+++ b/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
@@ -3,20 +3,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.IO;
using System.Linq;
-using Microsoft.OpenApi;
-using Microsoft.OpenApi.Any;
+using System.Text.Json;
+using System.Text.Json.Nodes;
using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Writers;
+using Microsoft.OpenApi.Models.Interfaces;
using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Net.OpenApiParser.Extensions;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Net.OpenApiParser.Types;
using WireMock.Net.OpenApiParser.Utils;
+using SystemTextJsonSerializer = System.Text.Json.JsonSerializer;
namespace WireMock.Net.OpenApiParser.Mappers;
@@ -39,56 +38,40 @@ internal class OpenApiPathsMapper
.OrderBy(p => p.Key)
.Select(p => MapPath(p.Key, p.Value, servers))
.SelectMany(x => x)
- .ToArray() ??
- Array.Empty();
+ .ToArray() ?? [];
}
- private IReadOnlyList MapPaths(OpenApiPaths? paths, IList servers)
+ private IReadOnlyList MapPath(string path, IOpenApiPathItem pathItem, IList servers)
{
- return paths?
- .OrderBy(p => p.Key)
- .Select(p => MapPath(p.Key, p.Value, servers))
- .SelectMany(x => x)
- .ToArray() ??
- Array.Empty();
- }
-
- private IReadOnlyList MapPath(string path, OpenApiPathItem pathItem, IList servers)
- {
- return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray();
+ return pathItem.Operations?.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray() ?? [];
}
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList servers)
{
- var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
- var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
- var headers = operation.Parameters.Where(p => p.In == ParameterLocation.Header);
+ var queryParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Query) ?? [];
+ var pathParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Path) ?? [];
+ var headers = operation.Parameters?.Where(p => p.In == ParameterLocation.Header) ?? [];
- var response = operation.Responses.FirstOrDefault();
+ var response = operation?.Responses?.FirstOrDefault() ?? new KeyValuePair();
- TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out string? responseContentType);
+ TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out var responseContentType);
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
var responseExample = responseContent?.Example;
var responseSchemaExample = responseContent?.Schema?.Example;
- var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) :
- responseSchemaExample != null ? MapOpenApiAnyToJToken(responseSchemaExample) :
- MapSchemaToObject(responseSchema);
+ var responseBody = responseExample ?? responseSchemaExample ?? MapSchemaToObject(responseSchema);
var requestBodyModel = new BodyModel();
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
{
var request = operation.RequestBody.Content;
- TryGetContent(request, out OpenApiMediaType? requestContent, out _);
+ TryGetContent(request, out var requestContent, out _);
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
var requestBodyExample = requestContent!.Example;
var requestBodySchemaExample = requestContent.Schema?.Example;
- var requestBodyMapped = requestBodyExample != null ? MapOpenApiAnyToJToken(requestBodyExample) :
- requestBodySchemaExample != null ? MapOpenApiAnyToJToken(requestBodySchemaExample) :
- MapSchemaToObject(requestBodySchema);
-
+ var requestBodyMapped = requestBodyExample ?? requestBodySchemaExample ?? MapSchemaToObject(requestBodySchema);
requestBodyModel = MapRequestBody(requestBodyMapped);
}
@@ -102,8 +85,8 @@ internal class OpenApiPathsMapper
Guid = Guid.NewGuid(),
Request = new RequestModel
{
- Methods = new[] { httpMethod },
- Path = MapBasePath(servers) + MapPathWithParameters(path, pathParameters),
+ Methods = [httpMethod],
+ Path = PathUtils.Combine(MapBasePath(servers), MapPathWithParameters(path, pathParameters)),
Params = MapQueryParameters(queryParameters),
Headers = MapRequestHeaders(headers),
Body = requestBodyModel
@@ -112,12 +95,12 @@ internal class OpenApiPathsMapper
{
StatusCode = httpStatusCode,
Headers = MapHeaders(responseContentType, response.Value?.Headers),
- BodyAsJson = body
+ BodyAsJson = responseBody != null ? JsonConvert.DeserializeObject(SystemTextJsonSerializer.Serialize(responseBody)) : null
}
};
}
- private BodyModel? MapRequestBody(object? requestBody)
+ private BodyModel? MapRequestBody(JsonNode? requestBody)
{
if (requestBody == null)
{
@@ -129,7 +112,7 @@ internal class OpenApiPathsMapper
Matcher = new MatcherModel
{
Name = "JsonMatcher",
- Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
+ Pattern = SystemTextJsonSerializer.Serialize(requestBody, new JsonSerializerOptions { WriteIndented = true }),
IgnoreCase = _settings.RequestBodyIgnoreCase
}
};
@@ -160,117 +143,103 @@ internal class OpenApiPathsMapper
return true;
}
- private object? MapSchemaToObject(OpenApiSchema? schema, string? name = null)
+ private JsonNode? MapSchemaToObject(IOpenApiSchema? schema)
{
if (schema == null)
{
return null;
}
- switch (schema.GetSchemaType())
+ switch (schema.GetSchemaType(out _))
{
- case SchemaType.Array:
- var jArray = new JArray();
- for (int i = 0; i < _settings.NumberOfArrayItems; i++)
+ case JsonSchemaType.Array:
+ var array = new JsonArray();
+ for (var i = 0; i < _settings.NumberOfArrayItems; i++)
{
- if (schema.Items.Properties.Count > 0)
+ if (schema.Items?.Properties?.Count > 0)
{
- var arrayItem = new JObject();
+ var item = new JsonObject();
foreach (var property in schema.Items.Properties)
{
- var objectValue = MapSchemaToObject(property.Value, property.Key);
- if (objectValue is JProperty jp)
- {
- arrayItem.Add(jp);
- }
- else
- {
- arrayItem.Add(new JProperty(property.Key, objectValue));
- }
+ item[property.Key] = MapSchemaToObject(property.Value);
}
- jArray.Add(arrayItem);
+ array.Add(item);
}
else
{
- var arrayItem = MapSchemaToObject(schema.Items, name: null); // Set name to null to force JObject instead of JProperty
- jArray.Add(arrayItem);
+ var arrayItem = MapSchemaToObject(schema.Items);
+ array.Add(arrayItem);
}
}
- if (schema.AllOf.Count > 0)
+ if (schema.AllOf?.Count > 0)
{
- jArray.Add(MapSchemaAllOfToObject(schema));
+ array.Add(MapSchemaAllOfToObject(schema));
}
- return jArray;
+ return array;
- case SchemaType.Boolean:
- case SchemaType.Integer:
- case SchemaType.Number:
- case SchemaType.String:
+ case JsonSchemaType.Boolean:
+ case JsonSchemaType.Integer:
+ case JsonSchemaType.Number:
+ case JsonSchemaType.String:
return _exampleValueGenerator.GetExampleValue(schema);
- case SchemaType.Object:
- var propertyAsJObject = new JObject();
- foreach (var schemaProperty in schema.Properties)
+ case JsonSchemaType.Object:
+ var propertyAsJsonObject = new JsonObject();
+ foreach (var schemaProperty in schema.Properties ?? new Dictionary())
{
- propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
+ propertyAsJsonObject[schemaProperty.Key] = MapPropertyAsJsonNode(schemaProperty.Value);
}
- if (schema.AllOf.Count > 0)
+ if (schema.AllOf?.Count > 0)
{
- foreach (var group in schema.AllOf.SelectMany(p => p.Properties).GroupBy(x => x.Key))
+ foreach (var group in schema.AllOf.SelectMany(p => p.Properties ?? new Dictionary()).GroupBy(x => x.Key))
{
- propertyAsJObject.Add(MapPropertyAsJObject(group.First().Value, group.Key));
+ propertyAsJsonObject[group.Key] = MapPropertyAsJsonNode(group.First().Value);
}
}
- return name != null ? new JProperty(name, propertyAsJObject) : propertyAsJObject;
+ return propertyAsJsonObject;
default:
return null;
}
}
- private JObject MapSchemaAllOfToObject(OpenApiSchema schema)
+ private JsonObject MapSchemaAllOfToObject(IOpenApiSchema schema)
{
- var arrayItem = new JObject();
- foreach (var property in schema.AllOf)
+ var arrayItem = new JsonObject();
+ foreach (var property in schema.AllOf ?? [])
{
- foreach (var item in property.Properties)
+ foreach (var item in property.Properties ?? new Dictionary())
{
- arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
+ arrayItem[item.Key] = MapPropertyAsJsonNode(item.Value);
}
}
return arrayItem;
}
- private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
+ private JsonNode? MapPropertyAsJsonNode(IOpenApiSchema openApiSchema)
{
- if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
+ var schemaType = openApiSchema.GetSchemaType(out _);
+ if (schemaType is JsonSchemaType.Object or JsonSchemaType.Array)
{
- var mapped = MapSchemaToObject(openApiSchema, key);
- if (mapped is JProperty jp)
- {
- return jp;
- }
-
- return new JProperty(key, mapped);
+ return MapSchemaToObject(openApiSchema);
}
- // bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
- return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
+ return _exampleValueGenerator.GetExampleValue(openApiSchema);
}
- private string MapPathWithParameters(string path, IEnumerable? parameters)
+ private string MapPathWithParameters(string path, IEnumerable? parameters)
{
if (parameters == null)
{
return path;
}
- string newPath = path;
+ var newPath = path;
foreach (var parameter in parameters)
{
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
@@ -280,93 +249,56 @@ internal class OpenApiPathsMapper
return newPath;
}
- private string MapBasePath(IList? servers)
+ private IDictionary? MapHeaders(string? responseContentType, IDictionary? headers)
{
- if (servers == null || servers.Count == 0)
- {
- return string.Empty;
- }
-
- OpenApiServer server = servers.First();
- if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
- {
- return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
- }
-
- return string.Empty;
- }
-
- private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
- {
- if (any == null)
- {
- return null;
- }
-
- using var outputString = new StringWriter();
- var writer = new OpenApiJsonWriter(outputString);
- any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
-
- if (any.AnyType == AnyType.Array)
- {
- return JArray.Parse(outputString.ToString());
- }
-
- return JObject.Parse(outputString.ToString());
- }
-
- private IDictionary? MapHeaders(string? responseContentType, IDictionary? headers)
- {
- var mappedHeaders = headers?.ToDictionary(
- item => item.Key,
- _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!
- ) ?? new Dictionary();
+ var mappedHeaders = headers?
+ .ToDictionary(item => item.Key, _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!) ?? new Dictionary();
if (!string.IsNullOrEmpty(responseContentType))
{
- mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
+ mappedHeaders.TryAdd(HeaderContentType, responseContentType);
}
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
}
- private IList? MapQueryParameters(IEnumerable queryParameters)
+ private IList? MapQueryParameters(IEnumerable queryParameters)
{
var list = queryParameters
.Where(req => req.Required)
.Select(qp => new ParamModel
{
- Name = qp.Name,
+ Name = qp.Name ?? string.Empty,
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
- Matchers = new[]
- {
+ Matchers =
+ [
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
- }
+ ]
})
.ToList();
return list.Any() ? list : null;
}
- private IList? MapRequestHeaders(IEnumerable headers)
+ private IList? MapRequestHeaders(IEnumerable headers)
{
var list = headers
.Where(req => req.Required)
.Select(qp => new HeaderModel
{
- Name = qp.Name,
+ Name = qp.Name ?? string.Empty,
IgnoreCase = _settings.HeaderPatternIgnoreCase,
- Matchers = new[]
- {
+ Matchers =
+ [
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
- }
+ ]
})
.ToList();
return list.Any() ? list : null;
}
- private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
+ private MatcherModel GetExampleMatcherModel(IOpenApiSchema? schema, ExampleValueType type)
{
return type switch
{
@@ -385,15 +317,31 @@ internal class OpenApiPathsMapper
};
}
- private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
+ private string GetExampleValueAsStringForSchemaType(IOpenApiSchema? schema)
{
var value = _exampleValueGenerator.GetExampleValue(schema);
- return value switch
+ if (value.GetValueKind() == JsonValueKind.String)
{
- string valueAsString => valueAsString,
+ return value.GetValue();
+ }
- _ => value.ToString(),
- };
+ return value.ToString();
+ }
+
+ private static string MapBasePath(IList? servers)
+ {
+ var server = servers?.FirstOrDefault();
+ if (server == null)
+ {
+ return string.Empty;
+ }
+
+ if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out var uriResult))
+ {
+ return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
+ }
+
+ return string.Empty;
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Properties/AssemblyInfo.cs b/src/WireMock.Net.OpenApiParser/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..fb354ea5
--- /dev/null
+++ b/src/WireMock.Net.OpenApiParser/Properties/AssemblyInfo.cs
@@ -0,0 +1,5 @@
+// Copyright © WireMock.Net
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
index 1d99b9ff..7c52339d 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
@@ -1,7 +1,7 @@
// Copyright © WireMock.Net
using System;
-using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
namespace WireMock.Net.OpenApiParser.Settings;
@@ -26,9 +26,9 @@ public interface IWireMockOpenApiParserExampleValues
float Float { get; }
///
- /// An example value for a Double.
+ /// An example value for a Decimal.
///
- double Double { get; }
+ decimal Decimal { get; }
///
/// An example value for a Date.
@@ -58,5 +58,5 @@ public interface IWireMockOpenApiParserExampleValues
///
/// OpenApi Schema to generate dynamic examples more accurate
///
- OpenApiSchema? Schema { get; set; }
+ IOpenApiSchema? Schema { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
index e179981c..c28e7016 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
@@ -1,7 +1,7 @@
// Copyright © WireMock.Net
using System;
-using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using RandomDataGenerator.FieldOptions;
using RandomDataGenerator.Randomizers;
@@ -22,7 +22,7 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
///
- public virtual double Double => RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d;
+ public virtual decimal Decimal => SafeConvertFloatToDecimal(RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f);
///
public virtual Func Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
@@ -40,5 +40,20 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
///
- public virtual OpenApiSchema? Schema { get; set; }
+ public virtual IOpenApiSchema? Schema { get; set; }
+
+ ///
+ /// Safely converts a float to a decimal, ensuring the value stays within the bounds of a decimal.
+ ///
+ /// The float value to convert.
+ /// A decimal value within the valid range of a decimal.
+ private static decimal SafeConvertFloatToDecimal(float value)
+ {
+ return value switch
+ {
+ < (float)decimal.MinValue => decimal.MinValue,
+ > (float)decimal.MaxValue => decimal.MaxValue,
+ _ => (decimal)value
+ };
+ }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
index f5e7f03e..4a43b424 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
@@ -2,6 +2,7 @@
using System;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
namespace WireMock.Net.OpenApiParser.Settings;
@@ -20,7 +21,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
public virtual float Float => 4.2f;
///
- public virtual double Double => 4.2d;
+ public virtual decimal Decimal => 4.2m;
///
public virtual Func Date { get; } = () => System.DateTime.UtcNow.Date;
@@ -29,7 +30,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
public virtual Func DateTime { get; } = () => System.DateTime.UtcNow;
///
- public virtual byte[] Bytes { get; } = { 48, 49, 50 };
+ public virtual byte[] Bytes { get; } = [48, 49, 50];
///
public virtual object Object => "example-object";
@@ -38,5 +39,5 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
public virtual string String => "example-string";
///
- public virtual OpenApiSchema? Schema { get; set; } = new();
+ public virtual IOpenApiSchema? Schema { get; set; } = new OpenApiSchema();
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs b/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs
deleted file mode 100644
index 4b5df64d..00000000
--- a/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright © WireMock.Net
-
-namespace WireMock.Net.OpenApiParser.Types;
-
-internal enum SchemaType
-{
- Object,
-
- Array,
-
- String,
-
- Integer,
-
- Number,
-
- Boolean,
-
- File,
-
- Unknown
-}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs b/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
index c0108295..e3178549 100644
--- a/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
+++ b/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
@@ -7,13 +7,16 @@ namespace WireMock.Net.OpenApiParser.Utils;
internal static class DateTimeUtils
{
+ private const string DateFormat = "yyyy-MM-dd";
+ private const string DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.fffzzz";
+
public static string ToRfc3339DateTime(DateTime dateTime)
{
- return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
+ return dateTime.ToString(DateTimeFormat, DateTimeFormatInfo.InvariantInfo);
}
public static string ToRfc3339Date(DateTime dateTime)
{
- return dateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
+ return dateTime.ToString(DateFormat, DateTimeFormatInfo.InvariantInfo);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs b/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
index 4039a358..153d4c67 100644
--- a/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
+++ b/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
@@ -1,8 +1,10 @@
// Copyright © WireMock.Net
+using System;
using System.Linq;
-using Microsoft.OpenApi.Any;
+using System.Text.Json.Nodes;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Models.Interfaces;
using Stef.Validation;
using WireMock.Net.OpenApiParser.Extensions;
using WireMock.Net.OpenApiParser.Settings;
@@ -36,82 +38,66 @@ internal class ExampleValueGenerator
}
}
- public object GetExampleValue(OpenApiSchema? schema)
+ public JsonNode GetExampleValue(IOpenApiSchema? schema)
{
var schemaExample = schema?.Example;
var schemaEnum = schema?.Enum?.FirstOrDefault();
_exampleValues.Schema = schema;
- switch (schema?.GetSchemaType())
+ switch (schema?.GetSchemaType(out _))
{
- case SchemaType.Boolean:
- var exampleBoolean = schemaExample as OpenApiBoolean;
- return exampleBoolean?.Value ?? _exampleValues.Boolean;
+ case JsonSchemaType.Boolean:
+ var exampleBoolean = schemaExample?.GetValue();
+ return exampleBoolean ?? _exampleValues.Boolean;
- case SchemaType.Integer:
- switch (schema?.GetSchemaFormat())
- {
- case SchemaFormat.Int64:
- var exampleLong = schemaExample as OpenApiLong;
- var enumLong = schemaEnum as OpenApiLong;
- var valueLongEnumOrExample = enumLong?.Value ?? exampleLong?.Value;
- return valueLongEnumOrExample ?? _exampleValues.Integer;
+ case JsonSchemaType.Integer:
+ var exampleInteger = schemaExample?.GetValue();
+ var enumInteger = schemaEnum?.GetValue();
+ var valueIntegerEnumOrExample = enumInteger ?? exampleInteger;
+ return valueIntegerEnumOrExample ?? _exampleValues.Integer;
- default:
- var exampleInteger = schemaExample as OpenApiInteger;
- var enumInteger = schemaEnum as OpenApiInteger;
- var valueIntegerEnumOrExample = enumInteger?.Value ?? exampleInteger?.Value;
- return valueIntegerEnumOrExample ?? _exampleValues.Integer;
- }
-
- case SchemaType.Number:
- switch (schema?.GetSchemaFormat())
+ case JsonSchemaType.Number:
+ switch (schema.GetSchemaFormat())
{
case SchemaFormat.Float:
- var exampleFloat = schemaExample as OpenApiFloat;
- var enumFloat = schemaEnum as OpenApiFloat;
- var valueFloatEnumOrExample = enumFloat?.Value ?? exampleFloat?.Value;
+ var exampleFloat = schemaExample?.GetValue();
+ var enumFloat = schemaEnum?.GetValue();
+ var valueFloatEnumOrExample = enumFloat ?? exampleFloat;
return valueFloatEnumOrExample ?? _exampleValues.Float;
default:
- var exampleDouble = schemaExample as OpenApiDouble;
- var enumDouble = schemaEnum as OpenApiDouble;
- var valueDoubleEnumOrExample = enumDouble?.Value ?? exampleDouble?.Value;
- return valueDoubleEnumOrExample ?? _exampleValues.Double;
+ var exampleDecimal = schemaExample?.GetValue();
+ var enumDecimal = schemaEnum?.GetValue();
+ var valueDecimalEnumOrExample = enumDecimal ?? exampleDecimal;
+ return valueDecimalEnumOrExample ?? _exampleValues.Decimal;
}
default:
switch (schema?.GetSchemaFormat())
{
case SchemaFormat.Date:
- var exampleDate = schemaExample as OpenApiDate;
- var enumDate = schemaEnum as OpenApiDate;
- var valueDateEnumOrExample = enumDate?.Value ?? exampleDate?.Value;
- return DateTimeUtils.ToRfc3339Date(valueDateEnumOrExample ?? _exampleValues.Date());
+ var exampleDate = schemaExample?.GetValue();
+ var enumDate = schemaEnum?.GetValue();
+ var valueDateEnumOrExample = enumDate ?? exampleDate;
+ return valueDateEnumOrExample ?? DateTimeUtils.ToRfc3339Date(_exampleValues.Date());
case SchemaFormat.DateTime:
- var exampleDateTime = schemaExample as OpenApiDateTime;
- var enumDateTime = schemaEnum as OpenApiDateTime;
- var valueDateTimeEnumOrExample = enumDateTime?.Value ?? exampleDateTime?.Value;
- return DateTimeUtils.ToRfc3339DateTime(valueDateTimeEnumOrExample?.DateTime ?? _exampleValues.DateTime());
+ var exampleDateTime = schemaExample?.GetValue();
+ var enumDateTime = schemaEnum?.GetValue();
+ var valueDateTimeEnumOrExample = enumDateTime ?? exampleDateTime;
+ return valueDateTimeEnumOrExample ?? DateTimeUtils.ToRfc3339DateTime(_exampleValues.DateTime());
case SchemaFormat.Byte:
- var exampleByte = schemaExample as OpenApiByte;
- var enumByte = schemaEnum as OpenApiByte;
- var valueByteEnumOrExample = enumByte?.Value ?? exampleByte?.Value;
- return valueByteEnumOrExample ?? _exampleValues.Bytes;
-
- case SchemaFormat.Binary:
- var exampleBinary = schemaExample as OpenApiBinary;
- var enumBinary = schemaEnum as OpenApiBinary;
- var valueBinaryEnumOrExample = enumBinary?.Value ?? exampleBinary?.Value;
- return valueBinaryEnumOrExample ?? _exampleValues.Object;
+ var exampleByte = schemaExample?.GetValue();
+ var enumByte = schemaEnum?.GetValue();
+ var valueByteEnumOrExample = enumByte ?? exampleByte;
+ return Convert.ToBase64String(valueByteEnumOrExample ?? _exampleValues.Bytes);
default:
- var exampleString = schemaExample as OpenApiString;
- var enumString = schemaEnum as OpenApiString;
- var valueStringEnumOrExample = enumString?.Value ?? exampleString?.Value;
+ var exampleString = schemaExample?.GetValue();
+ var enumString = schemaEnum?.GetValue();
+ var valueStringEnumOrExample = enumString ?? exampleString;
return valueStringEnumOrExample ?? _exampleValues.String;
}
}
diff --git a/src/WireMock.Net.OpenApiParser/Utils/PathUtils.cs b/src/WireMock.Net.OpenApiParser/Utils/PathUtils.cs
new file mode 100644
index 00000000..c46b3923
--- /dev/null
+++ b/src/WireMock.Net.OpenApiParser/Utils/PathUtils.cs
@@ -0,0 +1,27 @@
+// Copyright © WireMock.Net
+
+namespace WireMock.Net.OpenApiParser.Utils;
+
+internal static class PathUtils
+{
+ internal static string Combine(params string[] paths)
+ {
+ if (paths.Length == 0)
+ {
+ return string.Empty;
+ }
+
+ var result = paths[0].Trim().TrimEnd('/');
+
+ for (int i = 1; i < paths.Length; i++)
+ {
+ var nextPath = paths[i].Trim().TrimStart('/').TrimEnd('/');
+ if (!string.IsNullOrEmpty(nextPath))
+ {
+ result += '/' + nextPath;
+ }
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
index 4dea3733..d6053b02 100644
--- a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
+++ b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
@@ -2,7 +2,7 @@
An OpenApi (swagger) parser to generate MappingModel or mapping.json file.
- net46;netstandard2.0;netstandard2.1
+ net47;netstandard2.0;netstandard2.1;net8.0
true
wiremock;openapi;OAS;raml;converter;parser;openapiparser
{D3804228-91F4-4502-9595-39584E5AADAD}
@@ -20,12 +20,11 @@
-
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs b/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
index 782457ca..9db653d8 100644
--- a/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
+++ b/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
@@ -6,7 +6,8 @@ using System.IO;
using System.Text;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers;
+using Microsoft.OpenApi.Reader;
+using Microsoft.OpenApi.YamlReader;
using RamlToOpenApiConverter;
using WireMock.Admin.Mappings;
using WireMock.Net.OpenApiParser.Mappers;
@@ -19,7 +20,7 @@ namespace WireMock.Net.OpenApiParser;
///
public class WireMockOpenApiParser : IWireMockOpenApiParser
{
- private readonly OpenApiStreamReader _reader = new();
+ private static readonly OpenApiReaderSettings ReaderSettings = new();
///
[PublicAPI]
@@ -40,8 +41,7 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
}
else
{
- var reader = new OpenApiStreamReader();
- document = reader.Read(File.OpenRead(path), out diagnostic);
+ document = Read(File.OpenRead(path), out diagnostic);
}
return FromDocument(document, settings);
@@ -51,21 +51,21 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
[PublicAPI]
public IReadOnlyList FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
{
- return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers);
+ return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers ?? []);
}
///
[PublicAPI]
public IReadOnlyList FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
{
- return FromDocument(_reader.Read(stream, out diagnostic));
+ return FromDocument(Read(stream, out diagnostic));
}
///
[PublicAPI]
public IReadOnlyList FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
{
- return FromDocument(_reader.Read(stream, out diagnostic), settings);
+ return FromDocument(Read(stream, out diagnostic), settings);
}
///
@@ -81,4 +81,27 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
{
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
}
+
+ private static OpenApiDocument Read(Stream stream, out OpenApiDiagnostic diagnostic)
+ {
+ var reader = new OpenApiYamlReader();
+
+ if (stream is not MemoryStream memoryStream)
+ {
+ memoryStream = ReadStreamIntoMemoryStream(stream);
+ }
+
+ var result = reader.Read(memoryStream, ReaderSettings);
+
+ diagnostic = result.Diagnostic ?? new OpenApiDiagnostic();
+ return result.Document ?? throw new InvalidOperationException("The document is null.");
+ }
+
+ private static MemoryStream ReadStreamIntoMemoryStream(Stream stream)
+ {
+ var memoryStream = new MemoryStream();
+ stream.CopyTo(memoryStream);
+ memoryStream.Position = 0;
+ return memoryStream;
+ }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Extensions/StringExtensions.cs b/src/WireMock.Net/Extensions/StringExtensions.cs
new file mode 100644
index 00000000..4f57ad4a
--- /dev/null
+++ b/src/WireMock.Net/Extensions/StringExtensions.cs
@@ -0,0 +1,31 @@
+using System.Globalization;
+
+namespace WireMock.Extensions;
+
+internal static class StringExtensions
+{
+ // See https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core/
+ public static string GetDeterministicHashCodeAsString(this string str)
+ {
+ unchecked
+ {
+ int hash1 = (5381 << 16) + 5381;
+ int hash2 = hash1;
+
+ for (int i = 0; i < str.Length; i += 2)
+ {
+ hash1 = ((hash1 << 5) + hash1) ^ str[i];
+ if (i == str.Length - 1)
+ {
+ break;
+ }
+
+ hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
+ }
+
+ int result = hash1 + hash2 * 1566083941;
+
+ return result.ToString(CultureInfo.InvariantCulture).Replace('-', '_');
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs
index 4c206cc1..23f5cd58 100644
--- a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs
+++ b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs
@@ -84,20 +84,20 @@ public class LocalFileSystemHandler : IFileSystemHandler
public virtual byte[] ReadResponseBodyAsFile(string path)
{
Guard.NotNullOrEmpty(path);
- path = PathUtils.CleanPath(path)!;
+ path = FilePathUtils.CleanPath(path)!;
// If the file exists at the given path relative to the MappingsFolder, then return that.
// Else the path will just be as-is.
- return File.ReadAllBytes(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path);
+ return File.ReadAllBytes(File.Exists(FilePathUtils.Combine(GetMappingFolder(), path)) ? FilePathUtils.Combine(GetMappingFolder(), path) : path);
}
///
public virtual string ReadResponseBodyAsString(string path)
{
Guard.NotNullOrEmpty(path);
- path = PathUtils.CleanPath(path)!;
+ path = FilePathUtils.CleanPath(path)!;
// In case the path is a filename, the path will be adjusted to the MappingFolder.
// Else the path will just be as-is.
- return File.ReadAllText(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path);
+ return File.ReadAllText(File.Exists(FilePathUtils.Combine(GetMappingFolder(), path)) ? FilePathUtils.Combine(GetMappingFolder(), path) : path);
}
///
@@ -124,7 +124,7 @@ public class LocalFileSystemHandler : IFileSystemHandler
Guard.NotNullOrEmpty(filename);
Guard.NotNull(bytes);
- File.WriteAllBytes(PathUtils.Combine(folder, filename), bytes);
+ File.WriteAllBytes(FilePathUtils.Combine(folder, filename), bytes);
}
///
diff --git a/src/WireMock.Net/Models/BlockingQueue.cs b/src/WireMock.Net/Models/BlockingQueue.cs
new file mode 100644
index 00000000..30ca893e
--- /dev/null
+++ b/src/WireMock.Net/Models/BlockingQueue.cs
@@ -0,0 +1,85 @@
+// Copyright © WireMock.Net
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+
+namespace WireMock.Models;
+
+///
+internal class BlockingQueue(TimeSpan? readTimeout = null) : IBlockingQueue
+{
+ private readonly TimeSpan _readTimeout = readTimeout ?? TimeSpan.FromHours(1);
+ private readonly Queue _queue = new();
+ private readonly object _lockObject = new();
+
+ private bool _isClosed;
+
+ ///
+ /// Writes an item to the queue and signals that an item is available.
+ ///
+ /// The item to be added to the queue.
+ public void Write(T item)
+ {
+ lock (_lockObject)
+ {
+ if (_isClosed)
+ {
+ throw new InvalidOperationException("Cannot write to a closed queue.");
+ }
+
+ _queue.Enqueue(item);
+
+ // Signal that an item is available
+ Monitor.Pulse(_lockObject);
+ }
+ }
+
+ ///
+ /// Tries to read an item from the queue.
+ /// - waits until an item is available
+ /// - or the timeout occurs
+ /// - or queue is closed
+ ///
+ /// The item read from the queue, or default if the timeout occurs.
+ /// True if an item was successfully read; otherwise, false.
+ public bool TryRead([NotNullWhen(true)] out T? item)
+ {
+ lock (_lockObject)
+ {
+ // Wait until an item is available or timeout occurs
+ while (_queue.Count == 0 && !_isClosed)
+ {
+ // Wait with timeout
+ if (!Monitor.Wait(_lockObject, _readTimeout))
+ {
+ item = default;
+ return false;
+ }
+ }
+
+ // After waiting, check if we have items
+ if (_queue.Count == 0)
+ {
+ item = default;
+ return false;
+ }
+
+ item = _queue.Dequeue();
+ return item != null;
+ }
+ }
+
+ ///
+ /// Closes the queue and signals all waiting threads.
+ ///
+ public void Close()
+ {
+ lock (_lockObject)
+ {
+ _isClosed = true;
+ Monitor.PulseAll(_lockObject);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Models/BodyData.cs b/src/WireMock.Net/Models/BodyData.cs
index 2b214aca..d49fcbb4 100644
--- a/src/WireMock.Net/Models/BodyData.cs
+++ b/src/WireMock.Net/Models/BodyData.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
using WireMock.Models;
using WireMock.Types;
@@ -57,4 +58,10 @@ public class BodyData : IBodyData
///
public string? ProtoBufMessageType { get; set; }
#endregion
+
+ ///
+ public IBlockingQueue? SseStringQueue { get; set; }
+
+ ///
+ public Task? BodyAsSseStringTask { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Models/ProtoDefinitionData.cs b/src/WireMock.Net/Models/ProtoDefinitionData.cs
new file mode 100644
index 00000000..23ef5cdc
--- /dev/null
+++ b/src/WireMock.Net/Models/ProtoDefinitionData.cs
@@ -0,0 +1,39 @@
+// Copyright © WireMock.Net
+
+using System.Collections.Generic;
+using System.Linq;
+using Stef.Validation;
+
+namespace WireMock.Models;
+
+///
+/// A placeholder class for Proto Definitions.
+///
+public class ProtoDefinitionData
+{
+ private readonly IDictionary _filenameMappedToProtoDefinition;
+
+ internal ProtoDefinitionData(IDictionary filenameMappedToProtoDefinition)
+ {
+ _filenameMappedToProtoDefinition = filenameMappedToProtoDefinition;
+ }
+
+ ///
+ /// Get all the ProtoDefinitions.
+ /// Note: the main ProtoDefinition will be the first one in the list.
+ ///
+ /// The main ProtoDefinition filename.
+ public IReadOnlyList ToList(string mainProtoFilename)
+ {
+ Guard.NotNullOrEmpty(mainProtoFilename);
+
+ if (!_filenameMappedToProtoDefinition.TryGetValue(mainProtoFilename, out var mainProtoDefinition))
+ {
+ throw new KeyNotFoundException($"The ProtoDefinition with filename '{mainProtoFilename}' was not found.");
+ }
+
+ var list = new List { mainProtoDefinition };
+ list.AddRange(_filenameMappedToProtoDefinition.Where(kvp => kvp.Key != mainProtoFilename).Select(kvp => kvp.Value));
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
index b9645268..91d13ef4 100644
--- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
+++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
@@ -69,6 +69,13 @@ namespace WireMock.Owin.Mappers
return;
}
+ var bodyData = responseMessage.BodyData;
+ if (bodyData?.GetBodyType() == BodyType.SseString)
+ {
+ await HandleSseStringAsync(responseMessage, response, bodyData);
+ return;
+ }
+
byte[]? bytes;
switch (responseMessage.FaultType)
{
@@ -104,7 +111,7 @@ namespace WireMock.Owin.Mappers
}
}
- SetResponseHeaders(responseMessage, bytes, response);
+ SetResponseHeaders(responseMessage, bytes != null, response);
if (bytes != null)
{
@@ -121,6 +128,26 @@ namespace WireMock.Owin.Mappers
SetResponseTrailingHeaders(responseMessage, response);
}
+ private static async Task HandleSseStringAsync(IResponseMessage responseMessage, IResponse response, IBodyData bodyData)
+ {
+ if (bodyData.SseStringQueue == null)
+ {
+ return;
+ }
+
+ SetResponseHeaders(responseMessage, true, response);
+
+ string? text;
+ do
+ {
+ if (bodyData.SseStringQueue.TryRead(out text))
+ {
+ await response.WriteAsync(text);
+ await response.Body.FlushAsync();
+ }
+ } while (text != null);
+ }
+
private int MapStatusCode(int code)
{
if (_options.AllowOnlyDefinedHttpStatusCodeInResponse == true && !Enum.IsDefined(typeof(HttpStatusCode), code))
@@ -136,7 +163,8 @@ namespace WireMock.Owin.Mappers
return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage;
}
- private async Task GetNormalBodyAsync(IResponseMessage responseMessage) {
+ private async Task GetNormalBodyAsync(IResponseMessage responseMessage)
+ {
var bodyData = responseMessage.BodyData;
switch (bodyData?.GetBodyType())
{
@@ -172,13 +200,13 @@ namespace WireMock.Owin.Mappers
return null;
}
- private static void SetResponseHeaders(IResponseMessage responseMessage, byte[]? bytes, IResponse response)
+ private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, IResponse response)
{
// Force setting the Date header (#577)
AppendResponseHeader(
response,
HttpKnownHeaderNames.Date,
- [ DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture) ]
+ [DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.RFC1123Pattern, CultureInfo.InvariantCulture)]
);
// Set other headers
@@ -188,7 +216,7 @@ namespace WireMock.Owin.Mappers
var value = item.Value;
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
{
- action?.Invoke(response, bytes != null, value);
+ action?.Invoke(response, hasBody, value);
}
else
{
diff --git a/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs b/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs
index a5c5e1db..395e472e 100644
--- a/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs
+++ b/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs
@@ -1,5 +1,6 @@
// Copyright © WireMock.Net
+using System;
using System.Collections.Generic;
using WireMock.Matchers;
using WireMock.Matchers.Request;
@@ -12,7 +13,7 @@ public partial class Request
///
public IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
- return WithBodyAsProtoBuf([ protoDefinition ], messageType, matchBehaviour);
+ return WithBodyAsProtoBuf([protoDefinition], messageType, matchBehaviour);
}
///
@@ -36,12 +37,25 @@ public partial class Request
///
public IRequestBuilder WithBodyAsProtoBuf(string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
- return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => Mapping.ProtoDefinition!.Value, messageType));
+ return Add(new RequestMessageProtoBufMatcher(matchBehaviour, ProtoDefinitionFunc(), messageType));
}
///
public IRequestBuilder WithBodyAsProtoBuf(string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
- return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => Mapping.ProtoDefinition!.Value, messageType, matcher));
+ return Add(new RequestMessageProtoBufMatcher(matchBehaviour, ProtoDefinitionFunc(), messageType, matcher));
+ }
+
+ private Func ProtoDefinitionFunc()
+ {
+ return () =>
+ {
+ if (Mapping.ProtoDefinition == null)
+ {
+ throw new InvalidOperationException($"No ProtoDefinition defined on mapping '{Mapping.Guid}'. Please use the WireMockServerSettings to define ProtoDefinitions.");
+ }
+
+ return Mapping.ProtoDefinition.Value;
+ };
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs
index df9259c4..303ce15b 100644
--- a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs
+++ b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using JsonConverter.Abstractions;
+using WireMock.Models;
namespace WireMock.ResponseBuilders;
@@ -32,7 +33,7 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
IResponseBuilder WithBody(Func bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null);
///
- /// WithBody : Create a ... response based on a async callback function.
+ /// WithBody : Create a ... response based on an async callback function.
///
/// The async delegate to build the body.
/// The Body Destination format (SameAsSource, String or Bytes).
@@ -40,6 +41,14 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
/// A .
IResponseBuilder WithBody(Func> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null);
+ ///
+ /// WithBody : Create a ... response based on an async callback function.
+ ///
+ /// The async delegate to build the body.
+ /// The timeout to wait on new items in the queue. Default value is 1 hour.
+ /// A .
+ IResponseBuilder WithSseBody(Func, Task> bodyFactory, TimeSpan? timeout = null);
+
///
/// WithBody : Create a ... response based on a bytearray.
///
diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs b/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs
index 24135273..9c0aa7ed 100644
--- a/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs
+++ b/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs
@@ -51,6 +51,26 @@ public partial class Response
});
}
+ ///
+ public IResponseBuilder WithSseBody(Func, Task> bodyFactory, TimeSpan? timeout = null)
+ {
+ Guard.NotNull(bodyFactory);
+
+ var queue = new BlockingQueue(timeout);
+
+ return WithCallbackInternal(true, req => new ResponseMessage
+ {
+ BodyData = new BodyData
+ {
+ DetectedBodyType = BodyType.SseString,
+ SseStringQueue = queue,
+ BodyAsSseStringTask = bodyFactory(req, queue),
+ Encoding = Encoding.UTF8,
+ IsFuncUsed = "Func, Task>"
+ }
+ });
+ }
+
///
public IResponseBuilder WithBody(byte[] body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs
index 3840c9c3..5407159e 100644
--- a/src/WireMock.Net/Server/RespondWithAProvider.cs
+++ b/src/WireMock.Net/Server/RespondWithAProvider.cs
@@ -356,9 +356,12 @@ internal class RespondWithAProvider : IRespondWithAProvider
{
Guard.NotNull(protoDefinitionOrId);
+#if PROTOBUF
ProtoDefinition = ProtoDefinitionHelper.GetIdOrTexts(_settings, protoDefinitionOrId);
-
return this;
+#else
+ throw new NotSupportedException("The WithProtoDefinition method can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
+#endif
}
///
diff --git a/src/WireMock.Net/Server/WireMockServer.OpenApiParser.cs b/src/WireMock.Net/Server/WireMockServer.OpenApiParser.cs
index 694552b6..a56e8de9 100644
--- a/src/WireMock.Net/Server/WireMockServer.OpenApiParser.cs
+++ b/src/WireMock.Net/Server/WireMockServer.OpenApiParser.cs
@@ -25,7 +25,7 @@ public partial class WireMockServer
return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message);
}
#else
- return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.");
+ return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.6.x or lower.");
#endif
}
@@ -50,7 +50,7 @@ public partial class WireMockServer
return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message);
}
#else
- return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.");
+ return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.6.x or lower.");
#endif
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Util/FilePathUtils.cs b/src/WireMock.Net/Util/FilePathUtils.cs
new file mode 100644
index 00000000..fd8c2751
--- /dev/null
+++ b/src/WireMock.Net/Util/FilePathUtils.cs
@@ -0,0 +1,86 @@
+// Copyright © WireMock.Net
+
+using System.IO;
+using Stef.Validation;
+
+namespace WireMock.Util;
+
+internal static class FilePathUtils
+{
+ ///
+ /// Robust handling of the user defined path.
+ /// Also supports Unix and Windows platforms
+ ///
+ /// The path to clean
+ public static string? CleanPath(string? path)
+ {
+ return path?.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
+ }
+
+ ///
+ /// Removes leading directory separator chars from the filepath, which could break Path.Combine
+ ///
+ /// The path to remove the loading DirectorySeparatorChars
+ public static string? RemoveLeadingDirectorySeparators(string? path)
+ {
+ return path?.TrimStart(Path.DirectorySeparatorChar);
+ }
+
+ ///
+ /// Combine two paths
+ ///
+ /// The root path
+ /// The path
+ public static string Combine(string root, string? path)
+ {
+ Guard.NotNull(root);
+
+ var result = RemoveLeadingDirectorySeparators(path);
+ return result == null ? root : Path.Combine(root, result);
+ }
+
+ ///
+ /// Returns a relative path from one path to another.
+ ///
+ /// The source path the result should be relative to. This path is always considered to be a directory..
+ /// The destination path.
+ /// The relative path, or path if the paths don't share the same root.
+ public static string GetRelativePath(string relativeTo, string path)
+ {
+#if NETCOREAPP3_1 || NET5_0_OR_GREATER || NETSTANDARD2_1
+ return Path.GetRelativePath(relativeTo, path);
+#else
+ Guard.NotNull(relativeTo);
+ Guard.NotNull(path);
+
+ static string AppendDirectorySeparatorChar(string path)
+ {
+ // Append a slash only if the path is a directory and does not have a slash.
+ if (!Path.HasExtension(path) && !path.EndsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ return path + Path.DirectorySeparatorChar;
+ }
+
+ return path;
+ }
+
+ var fromUri = new System.Uri(AppendDirectorySeparatorChar(relativeTo));
+ var toUri = new System.Uri(AppendDirectorySeparatorChar(path));
+
+ if (fromUri.Scheme != toUri.Scheme)
+ {
+ return path;
+ }
+
+ var relativeUri = fromUri.MakeRelativeUri(toUri);
+ var relativePath = System.Uri.UnescapeDataString(relativeUri.ToString());
+
+ if (string.Equals(toUri.Scheme, "FILE", System.StringComparison.OrdinalIgnoreCase))
+ {
+ relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
+ }
+
+ return relativePath;
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Util/PathUtils.cs b/src/WireMock.Net/Util/PathUtils.cs
deleted file mode 100644
index 2ea460ff..00000000
--- a/src/WireMock.Net/Util/PathUtils.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright © WireMock.Net
-
-using System.IO;
-using Stef.Validation;
-
-namespace WireMock.Util;
-
-internal static class PathUtils
-{
- ///
- /// Robust handling of the user defined path.
- /// Also supports Unix and Windows platforms
- ///
- /// The path to clean
- public static string? CleanPath(string? path)
- {
- return path?.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
- }
-
- ///
- /// Removes leading directory separator chars from the filepath, which could break Path.Combine
- ///
- /// The path to remove the loading DirectorySeparatorChars
- public static string? RemoveLeadingDirectorySeparators(string? path)
- {
- return path?.TrimStart(new[] { Path.DirectorySeparatorChar });
- }
-
- ///
- /// Combine two paths
- ///
- /// The root path
- /// The path
- public static string Combine(string root, string? path)
- {
- Guard.NotNull(root);
-
- var result = RemoveLeadingDirectorySeparators(path);
- return result == null ? root : Path.Combine(root, result);
- }
-}
\ No newline at end of file
diff --git a/src/WireMock.Net/Util/ProtoDefinitionHelper.cs b/src/WireMock.Net/Util/ProtoDefinitionHelper.cs
index 91edc51e..d616abc2 100644
--- a/src/WireMock.Net/Util/ProtoDefinitionHelper.cs
+++ b/src/WireMock.Net/Util/ProtoDefinitionHelper.cs
@@ -1,12 +1,85 @@
// Copyright © WireMock.Net
+#if PROTOBUF
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using ProtoBufJsonConverter;
+using ProtoBufJsonConverter.Models;
+using Stef.Validation;
using WireMock.Models;
using WireMock.Settings;
namespace WireMock.Util;
-internal static class ProtoDefinitionHelper
+///
+/// Some helper methods for Proto Definitions.
+///
+public static class ProtoDefinitionHelper
{
+ ///
+ /// Builds a dictionary of ProtoDefinitions from a directory.
+ /// - The key will be the filename without extension.
+ /// - The value will be the ProtoDefinition with an extra comment with the relative path to each .proto file so it can be used by the WireMockProtoFileResolver.
+ ///
+ /// The directory to start from.
+ /// The token to monitor for cancellation requests. The default value is System.Threading.CancellationToken.None.
+ public static async Task FromDirectory(string directory, CancellationToken cancellationToken = default)
+ {
+ Guard.NotNullOrEmpty(directory);
+
+ var fileNameMappedToProtoDefinition = new Dictionary();
+ var filePaths = Directory.EnumerateFiles(directory, "*.proto", SearchOption.AllDirectories);
+
+ foreach (var filePath in filePaths)
+ {
+ // Get the relative path to the directory (note that this will be OS specific).
+ var relativePath = FilePathUtils.GetRelativePath(directory, filePath);
+
+ // Make it a valid proto import path
+ var protoRelativePath = relativePath.Replace(Path.DirectorySeparatorChar, '/');
+
+ // Build comment and get content from file.
+ var comment = $"// {protoRelativePath}";
+#if NETSTANDARD2_0
+ var content = File.ReadAllText(filePath);
+#else
+ var content = await File.ReadAllTextAsync(filePath, cancellationToken);
+#endif
+ // Only add the comment if it's not already defined.
+ var modifiedContent = !content.StartsWith(comment) ? $"{comment}\n{content}" : content;
+ var key = Path.GetFileNameWithoutExtension(filePath);
+
+ fileNameMappedToProtoDefinition.Add(key, modifiedContent);
+ }
+
+ var converter = SingletonFactory.GetInstance();
+ var resolver = new WireMockProtoFileResolver(fileNameMappedToProtoDefinition.Values);
+
+ var messageTypeMappedToWithProtoDefinition = new Dictionary();
+
+ foreach (var protoDefinition in fileNameMappedToProtoDefinition.Values)
+ {
+ var infoRequest = new GetInformationRequest(protoDefinition, resolver);
+
+ try
+ {
+ var info = await converter.GetInformationAsync(infoRequest, cancellationToken);
+ foreach (var messageType in info.MessageTypes)
+ {
+ messageTypeMappedToWithProtoDefinition[messageType.Key] = protoDefinition;
+ }
+ }
+ catch
+ {
+ // Ignore
+ }
+ }
+
+ return new ProtoDefinitionData(fileNameMappedToProtoDefinition);
+ }
+
internal static IdOrTexts GetIdOrTexts(WireMockServerSettings settings, params string[] protoDefinitionOrId)
{
switch (protoDefinitionOrId.Length)
@@ -19,9 +92,10 @@ internal static class ProtoDefinitionHelper
}
return new(null, protoDefinitionOrId);
-
+
default:
return new(null, protoDefinitionOrId);
}
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/WireMock.Net/Util/WireMockProtoFileResolver.cs b/src/WireMock.Net/Util/WireMockProtoFileResolver.cs
index cbae432c..e81893f2 100644
--- a/src/WireMock.Net/Util/WireMockProtoFileResolver.cs
+++ b/src/WireMock.Net/Util/WireMockProtoFileResolver.cs
@@ -7,18 +7,19 @@ using System.IO;
using System.Linq;
using ProtoBufJsonConverter;
using Stef.Validation;
+using WireMock.Extensions;
namespace WireMock.Util;
///
/// This resolver is used to resolve the extra ProtoDefinition files.
+///
/// It assumes that:
-/// - the first ProtoDefinition file is the main ProtoDefinition file.
-/// - the first commented line of each extra ProtoDefinition file is the filename which is used in the import of the other ProtoDefinition file(s).
+/// - The first commented line of each ProtoDefinition file is the filepath which is used in the import of the other ProtoDefinition file(s).
///
internal class WireMockProtoFileResolver : IProtoFileResolver
{
- private readonly Dictionary _files = new();
+ private readonly Dictionary _files = [];
public WireMockProtoFileResolver(IReadOnlyCollection protoDefinitions)
{
@@ -27,12 +28,19 @@ internal class WireMockProtoFileResolver : IProtoFileResolver
return;
}
- foreach (var extraProtoDefinition in protoDefinitions.Skip(1))
+ foreach (var extraProtoDefinition in protoDefinitions)
{
var firstNonEmptyLine = extraProtoDefinition.Split(['\r', '\n']).FirstOrDefault(l => !string.IsNullOrEmpty(l));
- if (firstNonEmptyLine != null && TryGetValidFileName(firstNonEmptyLine.TrimStart(['/', ' ']), out var validFileName))
+ if (firstNonEmptyLine != null)
{
- _files.Add(validFileName, extraProtoDefinition);
+ if (TryGetValidPath(firstNonEmptyLine.TrimStart(['/', ' ']), out var validPath))
+ {
+ _files.Add(validPath, extraProtoDefinition);
+ }
+ else
+ {
+ _files.Add(extraProtoDefinition.GetDeterministicHashCodeAsString(), extraProtoDefinition);
+ }
}
}
}
@@ -52,15 +60,15 @@ internal class WireMockProtoFileResolver : IProtoFileResolver
throw new FileNotFoundException($"The ProtoDefinition '{path}' was not found.");
}
- private static bool TryGetValidFileName(string fileName, [NotNullWhen(true)] out string? validFileName)
+ private static bool TryGetValidPath(string path, [NotNullWhen(true)] out string? validPath)
{
- if (!fileName.Any(c => Path.GetInvalidFileNameChars().Contains(c)))
+ if (!path.Any(c => Path.GetInvalidPathChars().Contains(c)))
{
- validFileName = fileName;
+ validPath = path;
return true;
}
- validFileName = null;
+ validPath = null;
return false;
}
}
diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj
index ce422f0b..168787c3 100644
--- a/src/WireMock.Net/WireMock.Net.csproj
+++ b/src/WireMock.Net/WireMock.Net.csproj
@@ -46,7 +46,7 @@
$(DefineConstants);USE_ASPNETCORE;NET46
-
+
$(DefineConstants);OPENAPIPARSER
@@ -195,17 +195,17 @@
-
-
+
-
+
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/ProtoDefinitionHelperTests.cs b/test/WireMock.Net.Tests/Grpc/ProtoDefinitionHelperTests.cs
new file mode 100644
index 00000000..7a501a25
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ProtoDefinitionHelperTests.cs
@@ -0,0 +1,73 @@
+// Copyright © WireMock.Net
+
+#if PROTOBUF
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using FluentAssertions;
+using WireMock.Util;
+using Xunit;
+
+namespace WireMock.Net.Tests.Grpc;
+
+public class ProtoDefinitionHelperTests
+{
+ [Fact]
+ public async Task FromDirectory_Greet_ShouldReturnModifiedProtoFiles()
+ {
+ // Arrange
+ var directory = Path.Combine(Directory.GetCurrentDirectory(), "Grpc", "Test");
+ var expectedFilename = "SubFolder/request.proto";
+ var expectedComment = $"// {expectedFilename}";
+
+ // Act
+ var protoDefinitionData = await ProtoDefinitionHelper.FromDirectory(directory);
+ var protoDefinitions = protoDefinitionData.ToList("greet");
+
+ // Assert
+ protoDefinitions.Should().HaveCount(2);
+ protoDefinitions[0].Should().StartWith("// greet.proto");
+ protoDefinitions[1].Should().StartWith(expectedComment);
+
+ // Arrange
+ var resolver = new WireMockProtoFileResolver(protoDefinitions);
+
+ // Act + Assert
+ resolver.Exists(expectedFilename).Should().BeTrue();
+ resolver.Exists("x").Should().BeFalse();
+
+ // Act + Assert
+ var text = await resolver.OpenText(expectedFilename).ReadToEndAsync();
+ text.Should().StartWith(expectedComment);
+ System.Action action = () => resolver.OpenText("x");
+ action.Should().Throw();
+ }
+
+ [Fact]
+ public async Task FromDirectory_OpenTelemetry_ShouldReturnModifiedProtoFiles()
+ {
+ // Arrange
+ var directory = Path.Combine(Directory.GetCurrentDirectory(), "Grpc", "ot");
+
+ // Act
+ var protoDefinitionData = await ProtoDefinitionHelper.FromDirectory(directory);
+ var protoDefinitions = protoDefinitionData.ToList("trace_service");
+
+ // Assert
+ protoDefinitions.Should().HaveCount(10);
+
+ var responseBytes = await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(
+ protoDefinitions,
+ "OpenTelemetry.Proto.Collector.Trace.V1.ExportTracePartialSuccess",
+ new
+ {
+ rejected_spans = 1,
+ error_message = "abc"
+ }
+ );
+
+ // Assert
+ Convert.ToBase64String(responseBytes).Should().Be("AAAAAAcIARIDYWJj");
+ }
+}
+#endif
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/Test/SubFolder/request.proto b/test/WireMock.Net.Tests/Grpc/Test/SubFolder/request.proto
new file mode 100644
index 00000000..28abb822
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/Test/SubFolder/request.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package greet;
+
+message HelloRequest {
+ string name = 1;
+}
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/Test/greet.proto b/test/WireMock.Net.Tests/Grpc/Test/greet.proto
new file mode 100644
index 00000000..4b327037
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/Test/greet.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+import "SubFolder/request.proto";
+
+package greet;
+
+service Greeter {
+ rpc SayHello (HelloRequest) returns (HelloReply);
+}
+
+message HelloReply {
+ string message = 1;
+}
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/README.md b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/README.md
new file mode 100644
index 00000000..f82dbb02
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/README.md
@@ -0,0 +1,10 @@
+# OpenTelemetry Collector Proto
+
+This package describes the OpenTelemetry collector protocol.
+
+## Packages
+
+1. `common` package contains the common messages shared between different services.
+2. `trace` package contains the Trace Service protos.
+3. `metrics` package contains the Metrics Service protos.
+4. `logs` package contains the Logs Service protos.
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service.proto
new file mode 100644
index 00000000..8260d8aa
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service.proto
@@ -0,0 +1,79 @@
+// Copyright 2020, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.collector.logs.v1;
+
+import "opentelemetry/proto/logs/v1/logs.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Collector.Logs.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.collector.logs.v1";
+option java_outer_classname = "LogsServiceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/collector/logs/v1";
+
+// Service that can be used to push logs between one Application instrumented with
+// OpenTelemetry and an collector, or between an collector and a central collector (in this
+// case logs are sent/received to/from multiple Applications).
+service LogsService {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ rpc Export(ExportLogsServiceRequest) returns (ExportLogsServiceResponse) {}
+}
+
+message ExportLogsServiceRequest {
+ // An array of ResourceLogs.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ repeated opentelemetry.proto.logs.v1.ResourceLogs resource_logs = 1;
+}
+
+message ExportLogsServiceResponse {
+ // The details of a partially successful export request.
+ //
+ // If the request is only partially accepted
+ // (i.e. when the server accepts only parts of the data and rejects the rest)
+ // the server MUST initialize the `partial_success` field and MUST
+ // set the `rejected_` with the number of items it rejected.
+ //
+ // Servers MAY also make use of the `partial_success` field to convey
+ // warnings/suggestions to senders even when the request was fully accepted.
+ // In such cases, the `rejected_` MUST have a value of `0` and
+ // the `error_message` MUST be non-empty.
+ //
+ // A `partial_success` message with an empty value (rejected_ = 0 and
+ // `error_message` = "") is equivalent to it not being set/present. Senders
+ // SHOULD interpret it the same way as in the full success case.
+ ExportLogsPartialSuccess partial_success = 1;
+}
+
+message ExportLogsPartialSuccess {
+ // The number of rejected log records.
+ //
+ // A `rejected_` field holding a `0` value indicates that the
+ // request was fully accepted.
+ int64 rejected_log_records = 1;
+
+ // A developer-facing human-readable message in English. It should be used
+ // either to explain why the server rejected parts of the data during a partial
+ // success or to convey warnings/suggestions during a full success. The message
+ // should offer guidance on how users can address such issues.
+ //
+ // error_message is an optional field. An error_message with an empty value
+ // is equivalent to it not being set.
+ string error_message = 2;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service_http.yaml b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service_http.yaml
new file mode 100644
index 00000000..507473b9
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/logs/v1/logs_service_http.yaml
@@ -0,0 +1,9 @@
+# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the
+# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway.
+type: google.api.Service
+config_version: 3
+http:
+ rules:
+ - selector: opentelemetry.proto.collector.logs.v1.LogsService.Export
+ post: /v1/logs
+ body: "*"
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service.proto
new file mode 100644
index 00000000..dd48f1ad
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service.proto
@@ -0,0 +1,79 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.collector.metrics.v1;
+
+import "opentelemetry/proto/metrics/v1/metrics.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Collector.Metrics.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.collector.metrics.v1";
+option java_outer_classname = "MetricsServiceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/collector/metrics/v1";
+
+// Service that can be used to push metrics between one Application
+// instrumented with OpenTelemetry and a collector, or between a collector and a
+// central collector.
+service MetricsService {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ rpc Export(ExportMetricsServiceRequest) returns (ExportMetricsServiceResponse) {}
+}
+
+message ExportMetricsServiceRequest {
+ // An array of ResourceMetrics.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ repeated opentelemetry.proto.metrics.v1.ResourceMetrics resource_metrics = 1;
+}
+
+message ExportMetricsServiceResponse {
+ // The details of a partially successful export request.
+ //
+ // If the request is only partially accepted
+ // (i.e. when the server accepts only parts of the data and rejects the rest)
+ // the server MUST initialize the `partial_success` field and MUST
+ // set the `rejected_` with the number of items it rejected.
+ //
+ // Servers MAY also make use of the `partial_success` field to convey
+ // warnings/suggestions to senders even when the request was fully accepted.
+ // In such cases, the `rejected_` MUST have a value of `0` and
+ // the `error_message` MUST be non-empty.
+ //
+ // A `partial_success` message with an empty value (rejected_ = 0 and
+ // `error_message` = "") is equivalent to it not being set/present. Senders
+ // SHOULD interpret it the same way as in the full success case.
+ ExportMetricsPartialSuccess partial_success = 1;
+}
+
+message ExportMetricsPartialSuccess {
+ // The number of rejected data points.
+ //
+ // A `rejected_` field holding a `0` value indicates that the
+ // request was fully accepted.
+ int64 rejected_data_points = 1;
+
+ // A developer-facing human-readable message in English. It should be used
+ // either to explain why the server rejected parts of the data during a partial
+ // success or to convey warnings/suggestions during a full success. The message
+ // should offer guidance on how users can address such issues.
+ //
+ // error_message is an optional field. An error_message with an empty value
+ // is equivalent to it not being set.
+ string error_message = 2;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml
new file mode 100644
index 00000000..a5456502
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml
@@ -0,0 +1,9 @@
+# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the
+# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway.
+type: google.api.Service
+config_version: 3
+http:
+ rules:
+ - selector: opentelemetry.proto.collector.metrics.v1.MetricsService.Export
+ post: /v1/metrics
+ body: "*"
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service.proto
new file mode 100644
index 00000000..ab2433ed
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service.proto
@@ -0,0 +1,78 @@
+// Copyright 2023, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.collector.profiles.v1development;
+
+import "opentelemetry/proto/profiles/v1development/profiles.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Collector.Profiles.V1Development";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.collector.profiles.v1development";
+option java_outer_classname = "ProfilesServiceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/collector/profiles/v1development";
+
+// Service that can be used to push profiles between one Application instrumented with
+// OpenTelemetry and a collector, or between a collector and a central collector.
+service ProfilesService {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ rpc Export(ExportProfilesServiceRequest) returns (ExportProfilesServiceResponse) {}
+}
+
+message ExportProfilesServiceRequest {
+ // An array of ResourceProfiles.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ repeated opentelemetry.proto.profiles.v1development.ResourceProfiles resource_profiles = 1;
+}
+
+message ExportProfilesServiceResponse {
+ // The details of a partially successful export request.
+ //
+ // If the request is only partially accepted
+ // (i.e. when the server accepts only parts of the data and rejects the rest)
+ // the server MUST initialize the `partial_success` field and MUST
+ // set the `rejected_` with the number of items it rejected.
+ //
+ // Servers MAY also make use of the `partial_success` field to convey
+ // warnings/suggestions to senders even when the request was fully accepted.
+ // In such cases, the `rejected_` MUST have a value of `0` and
+ // the `error_message` MUST be non-empty.
+ //
+ // A `partial_success` message with an empty value (rejected_ = 0 and
+ // `error_message` = "") is equivalent to it not being set/present. Senders
+ // SHOULD interpret it the same way as in the full success case.
+ ExportProfilesPartialSuccess partial_success = 1;
+}
+
+message ExportProfilesPartialSuccess {
+ // The number of rejected profiles.
+ //
+ // A `rejected_` field holding a `0` value indicates that the
+ // request was fully accepted.
+ int64 rejected_profiles = 1;
+
+ // A developer-facing human-readable message in English. It should be used
+ // either to explain why the server rejected parts of the data during a partial
+ // success or to convey warnings/suggestions during a full success. The message
+ // should offer guidance on how users can address such issues.
+ //
+ // error_message is an optional field. An error_message with an empty value
+ // is equivalent to it not being set.
+ string error_message = 2;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service_http.yaml b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service_http.yaml
new file mode 100644
index 00000000..6b3b91da
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/profiles/v1development/profiles_service_http.yaml
@@ -0,0 +1,9 @@
+# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the
+# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway.
+type: google.api.Service
+config_version: 3
+http:
+ rules:
+ - selector: opentelemetry.proto.collector.profiles.v1development.ProfilesService.Export
+ post: /v1development/profiles
+ body: "*"
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service.proto
new file mode 100644
index 00000000..d6fe67f9
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service.proto
@@ -0,0 +1,79 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.collector.trace.v1;
+
+import "opentelemetry/proto/trace/v1/trace.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Collector.Trace.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.collector.trace.v1";
+option java_outer_classname = "TraceServiceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/collector/trace/v1";
+
+// Service that can be used to push spans between one Application instrumented with
+// OpenTelemetry and a collector, or between a collector and a central collector (in this
+// case spans are sent/received to/from multiple Applications).
+service TraceService {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ rpc Export(ExportTraceServiceRequest) returns (ExportTraceServiceResponse) {}
+}
+
+message ExportTraceServiceRequest {
+ // An array of ResourceSpans.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ repeated opentelemetry.proto.trace.v1.ResourceSpans resource_spans = 1;
+}
+
+message ExportTraceServiceResponse {
+ // The details of a partially successful export request.
+ //
+ // If the request is only partially accepted
+ // (i.e. when the server accepts only parts of the data and rejects the rest)
+ // the server MUST initialize the `partial_success` field and MUST
+ // set the `rejected_` with the number of items it rejected.
+ //
+ // Servers MAY also make use of the `partial_success` field to convey
+ // warnings/suggestions to senders even when the request was fully accepted.
+ // In such cases, the `rejected_` MUST have a value of `0` and
+ // the `error_message` MUST be non-empty.
+ //
+ // A `partial_success` message with an empty value (rejected_ = 0 and
+ // `error_message` = "") is equivalent to it not being set/present. Senders
+ // SHOULD interpret it the same way as in the full success case.
+ ExportTracePartialSuccess partial_success = 1;
+}
+
+message ExportTracePartialSuccess {
+ // The number of rejected spans.
+ //
+ // A `rejected_` field holding a `0` value indicates that the
+ // request was fully accepted.
+ int64 rejected_spans = 1;
+
+ // A developer-facing human-readable message in English. It should be used
+ // either to explain why the server rejected parts of the data during a partial
+ // success or to convey warnings/suggestions during a full success. The message
+ // should offer guidance on how users can address such issues.
+ //
+ // error_message is an optional field. An error_message with an empty value
+ // is equivalent to it not being set.
+ string error_message = 2;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml
new file mode 100644
index 00000000..d091b3a8
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml
@@ -0,0 +1,9 @@
+# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the
+# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway.
+type: google.api.Service
+config_version: 3
+http:
+ rules:
+ - selector: opentelemetry.proto.collector.trace.v1.TraceService.Export
+ post: /v1/traces
+ body: "*"
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/common/v1/common.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/common/v1/common.proto
new file mode 100644
index 00000000..ff8a21a1
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/common/v1/common.proto
@@ -0,0 +1,81 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.common.v1;
+
+option csharp_namespace = "OpenTelemetry.Proto.Common.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.common.v1";
+option java_outer_classname = "CommonProto";
+option go_package = "go.opentelemetry.io/proto/otlp/common/v1";
+
+// AnyValue is used to represent any type of attribute value. AnyValue may contain a
+// primitive value such as a string or integer or it may contain an arbitrary nested
+// object containing arrays, key-value lists and primitives.
+message AnyValue {
+ // The value is one of the listed fields. It is valid for all values to be unspecified
+ // in which case this AnyValue is considered to be "empty".
+ oneof value {
+ string string_value = 1;
+ bool bool_value = 2;
+ int64 int_value = 3;
+ double double_value = 4;
+ ArrayValue array_value = 5;
+ KeyValueList kvlist_value = 6;
+ bytes bytes_value = 7;
+ }
+}
+
+// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message
+// since oneof in AnyValue does not allow repeated fields.
+message ArrayValue {
+ // Array of values. The array may be empty (contain 0 elements).
+ repeated AnyValue values = 1;
+}
+
+// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message
+// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need
+// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to
+// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches
+// are semantically equivalent.
+message KeyValueList {
+ // A collection of key/value pairs of key-value pairs. The list may be empty (may
+ // contain 0 elements).
+ // The keys MUST be unique (it is not allowed to have more than one
+ // value with the same key).
+ repeated KeyValue values = 1;
+}
+
+// KeyValue is a key-value pair that is used to store Span attributes, Link
+// attributes, etc.
+message KeyValue {
+ string key = 1;
+ AnyValue value = 2;
+}
+
+// InstrumentationScope is a message representing the instrumentation scope information
+// such as the fully qualified name and version.
+message InstrumentationScope {
+ // An empty instrumentation scope name means the name is unknown.
+ string name = 1;
+ string version = 2;
+
+ // Additional attributes that describe the scope. [Optional].
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated KeyValue attributes = 3;
+ uint32 dropped_attributes_count = 4;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/logs/v1/logs.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/logs/v1/logs.proto
new file mode 100644
index 00000000..261d2291
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/logs/v1/logs.proto
@@ -0,0 +1,227 @@
+// Copyright 2020, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.logs.v1;
+
+import "opentelemetry/proto/common/v1/common.proto";
+import "opentelemetry/proto/resource/v1/resource.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Logs.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.logs.v1";
+option java_outer_classname = "LogsProto";
+option go_package = "go.opentelemetry.io/proto/otlp/logs/v1";
+
+// LogsData represents the logs data that can be stored in a persistent storage,
+// OR can be embedded by other protocols that transfer OTLP logs data but do not
+// implement the OTLP protocol.
+//
+// The main difference between this message and collector protocol is that
+// in this message there will not be any "control" or "metadata" specific to
+// OTLP protocol.
+//
+// When new fields are added into this message, the OTLP request MUST be updated
+// as well.
+message LogsData {
+ // An array of ResourceLogs.
+ // For data coming from a single resource this array will typically contain
+ // one element. Intermediary nodes that receive data from multiple origins
+ // typically batch the data before forwarding further and in that case this
+ // array will contain multiple elements.
+ repeated ResourceLogs resource_logs = 1;
+}
+
+// A collection of ScopeLogs from a Resource.
+message ResourceLogs {
+ reserved 1000;
+
+ // The resource for the logs in this message.
+ // If this field is not set then resource info is unknown.
+ opentelemetry.proto.resource.v1.Resource resource = 1;
+
+ // A list of ScopeLogs that originate from a resource.
+ repeated ScopeLogs scope_logs = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the resource data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to the data in the "resource" field. It does not apply
+ // to the data in the "scope_logs" field which have their own schema_url field.
+ string schema_url = 3;
+}
+
+// A collection of Logs produced by a Scope.
+message ScopeLogs {
+ // The instrumentation scope information for the logs in this message.
+ // Semantically when InstrumentationScope isn't set, it is equivalent with
+ // an empty instrumentation scope name (unknown).
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
+
+ // A list of log records.
+ repeated LogRecord log_records = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the log data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to all logs in the "logs" field.
+ string schema_url = 3;
+}
+
+// Possible values for LogRecord.SeverityNumber.
+enum SeverityNumber {
+ // UNSPECIFIED is the default SeverityNumber, it MUST NOT be used.
+ SEVERITY_NUMBER_UNSPECIFIED = 0;
+ SEVERITY_NUMBER_TRACE = 1;
+ SEVERITY_NUMBER_TRACE2 = 2;
+ SEVERITY_NUMBER_TRACE3 = 3;
+ SEVERITY_NUMBER_TRACE4 = 4;
+ SEVERITY_NUMBER_DEBUG = 5;
+ SEVERITY_NUMBER_DEBUG2 = 6;
+ SEVERITY_NUMBER_DEBUG3 = 7;
+ SEVERITY_NUMBER_DEBUG4 = 8;
+ SEVERITY_NUMBER_INFO = 9;
+ SEVERITY_NUMBER_INFO2 = 10;
+ SEVERITY_NUMBER_INFO3 = 11;
+ SEVERITY_NUMBER_INFO4 = 12;
+ SEVERITY_NUMBER_WARN = 13;
+ SEVERITY_NUMBER_WARN2 = 14;
+ SEVERITY_NUMBER_WARN3 = 15;
+ SEVERITY_NUMBER_WARN4 = 16;
+ SEVERITY_NUMBER_ERROR = 17;
+ SEVERITY_NUMBER_ERROR2 = 18;
+ SEVERITY_NUMBER_ERROR3 = 19;
+ SEVERITY_NUMBER_ERROR4 = 20;
+ SEVERITY_NUMBER_FATAL = 21;
+ SEVERITY_NUMBER_FATAL2 = 22;
+ SEVERITY_NUMBER_FATAL3 = 23;
+ SEVERITY_NUMBER_FATAL4 = 24;
+}
+
+// LogRecordFlags represents constants used to interpret the
+// LogRecord.flags field, which is protobuf 'fixed32' type and is to
+// be used as bit-fields. Each non-zero value defined in this enum is
+// a bit-mask. To extract the bit-field, for example, use an
+// expression like:
+//
+// (logRecord.flags & LOG_RECORD_FLAGS_TRACE_FLAGS_MASK)
+//
+enum LogRecordFlags {
+ // The zero value for the enum. Should not be used for comparisons.
+ // Instead use bitwise "and" with the appropriate mask as shown above.
+ LOG_RECORD_FLAGS_DO_NOT_USE = 0;
+
+ // Bits 0-7 are used for trace flags.
+ LOG_RECORD_FLAGS_TRACE_FLAGS_MASK = 0x000000FF;
+
+ // Bits 8-31 are reserved for future use.
+}
+
+// A log record according to OpenTelemetry Log Data Model:
+// https://github.com/open-telemetry/oteps/blob/main/text/logs/0097-log-data-model.md
+message LogRecord {
+ reserved 4;
+
+ // time_unix_nano is the time when the event occurred.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ // Value of 0 indicates unknown or missing timestamp.
+ fixed64 time_unix_nano = 1;
+
+ // Time when the event was observed by the collection system.
+ // For events that originate in OpenTelemetry (e.g. using OpenTelemetry Logging SDK)
+ // this timestamp is typically set at the generation time and is equal to Timestamp.
+ // For events originating externally and collected by OpenTelemetry (e.g. using
+ // Collector) this is the time when OpenTelemetry's code observed the event measured
+ // by the clock of the OpenTelemetry code. This field MUST be set once the event is
+ // observed by OpenTelemetry.
+ //
+ // For converting OpenTelemetry log data to formats that support only one timestamp or
+ // when receiving OpenTelemetry log data by recipients that support only one timestamp
+ // internally the following logic is recommended:
+ // - Use time_unix_nano if it is present, otherwise use observed_time_unix_nano.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ // Value of 0 indicates unknown or missing timestamp.
+ fixed64 observed_time_unix_nano = 11;
+
+ // Numerical value of the severity, normalized to values described in Log Data Model.
+ // [Optional].
+ SeverityNumber severity_number = 2;
+
+ // The severity text (also known as log level). The original string representation as
+ // it is known at the source. [Optional].
+ string severity_text = 3;
+
+ // A value containing the body of the log record. Can be for example a human-readable
+ // string message (including multi-line) describing the event in a free form or it can
+ // be a structured data composed of arrays and maps of other values. [Optional].
+ opentelemetry.proto.common.v1.AnyValue body = 5;
+
+ // Additional attributes that describe the specific event occurrence. [Optional].
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 6;
+ uint32 dropped_attributes_count = 7;
+
+ // Flags, a bit field. 8 least significant bits are the trace flags as
+ // defined in W3C Trace Context specification. 24 most significant bits are reserved
+ // and must be set to 0. Readers must not assume that 24 most significant bits
+ // will be zero and must correctly mask the bits when reading 8-bit trace flag (use
+ // flags & LOG_RECORD_FLAGS_TRACE_FLAGS_MASK). [Optional].
+ fixed32 flags = 8;
+
+ // A unique identifier for a trace. All logs from the same trace share
+ // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR
+ // of length other than 16 bytes is considered invalid (empty string in OTLP/JSON
+ // is zero-length and thus is also invalid).
+ //
+ // This field is optional.
+ //
+ // The receivers SHOULD assume that the log record is not associated with a
+ // trace if any of the following is true:
+ // - the field is not present,
+ // - the field contains an invalid value.
+ bytes trace_id = 9;
+
+ // A unique identifier for a span within a trace, assigned when the span
+ // is created. The ID is an 8-byte array. An ID with all zeroes OR of length
+ // other than 8 bytes is considered invalid (empty string in OTLP/JSON
+ // is zero-length and thus is also invalid).
+ //
+ // This field is optional. If the sender specifies a valid span_id then it SHOULD also
+ // specify a valid trace_id.
+ //
+ // The receivers SHOULD assume that the log record is not associated with a
+ // span if any of the following is true:
+ // - the field is not present,
+ // - the field contains an invalid value.
+ bytes span_id = 10;
+
+ // A unique identifier of event category/type.
+ // All events with the same event_name are expected to conform to the same
+ // schema for both their attributes and their body.
+ //
+ // Recommended to be fully qualified and short (no longer than 256 characters).
+ //
+ // Presence of event_name on the log record identifies this record
+ // as an event.
+ //
+ // [Optional].
+ //
+ // Status: [Development]
+ string event_name = 12;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/metrics/v1/metrics.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/metrics/v1/metrics.proto
new file mode 100644
index 00000000..a42e51a6
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/metrics/v1/metrics.proto
@@ -0,0 +1,719 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.metrics.v1;
+
+import "opentelemetry/proto/common/v1/common.proto";
+import "opentelemetry/proto/resource/v1/resource.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Metrics.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.metrics.v1";
+option java_outer_classname = "MetricsProto";
+option go_package = "go.opentelemetry.io/proto/otlp/metrics/v1";
+
+// MetricsData represents the metrics data that can be stored in a persistent
+// storage, OR can be embedded by other protocols that transfer OTLP metrics
+// data but do not implement the OTLP protocol.
+//
+// MetricsData
+// └─── ResourceMetrics
+// ├── Resource
+// ├── SchemaURL
+// └── ScopeMetrics
+// ├── Scope
+// ├── SchemaURL
+// └── Metric
+// ├── Name
+// ├── Description
+// ├── Unit
+// └── data
+// ├── Gauge
+// ├── Sum
+// ├── Histogram
+// ├── ExponentialHistogram
+// └── Summary
+//
+// The main difference between this message and collector protocol is that
+// in this message there will not be any "control" or "metadata" specific to
+// OTLP protocol.
+//
+// When new fields are added into this message, the OTLP request MUST be updated
+// as well.
+message MetricsData {
+ // An array of ResourceMetrics.
+ // For data coming from a single resource this array will typically contain
+ // one element. Intermediary nodes that receive data from multiple origins
+ // typically batch the data before forwarding further and in that case this
+ // array will contain multiple elements.
+ repeated ResourceMetrics resource_metrics = 1;
+}
+
+// A collection of ScopeMetrics from a Resource.
+message ResourceMetrics {
+ reserved 1000;
+
+ // The resource for the metrics in this message.
+ // If this field is not set then no resource info is known.
+ opentelemetry.proto.resource.v1.Resource resource = 1;
+
+ // A list of metrics that originate from a resource.
+ repeated ScopeMetrics scope_metrics = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the resource data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to the data in the "resource" field. It does not apply
+ // to the data in the "scope_metrics" field which have their own schema_url field.
+ string schema_url = 3;
+}
+
+// A collection of Metrics produced by an Scope.
+message ScopeMetrics {
+ // The instrumentation scope information for the metrics in this message.
+ // Semantically when InstrumentationScope isn't set, it is equivalent with
+ // an empty instrumentation scope name (unknown).
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
+
+ // A list of metrics that originate from an instrumentation library.
+ repeated Metric metrics = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the metric data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to all metrics in the "metrics" field.
+ string schema_url = 3;
+}
+
+// Defines a Metric which has one or more timeseries. The following is a
+// brief summary of the Metric data model. For more details, see:
+//
+// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md
+//
+// The data model and relation between entities is shown in the
+// diagram below. Here, "DataPoint" is the term used to refer to any
+// one of the specific data point value types, and "points" is the term used
+// to refer to any one of the lists of points contained in the Metric.
+//
+// - Metric is composed of a metadata and data.
+// - Metadata part contains a name, description, unit.
+// - Data is one of the possible types (Sum, Gauge, Histogram, Summary).
+// - DataPoint contains timestamps, attributes, and one of the possible value type
+// fields.
+//
+// Metric
+// +------------+
+// |name |
+// |description |
+// |unit | +------------------------------------+
+// |data |---> |Gauge, Sum, Histogram, Summary, ... |
+// +------------+ +------------------------------------+
+//
+// Data [One of Gauge, Sum, Histogram, Summary, ...]
+// +-----------+
+// |... | // Metadata about the Data.
+// |points |--+
+// +-----------+ |
+// | +---------------------------+
+// | |DataPoint 1 |
+// v |+------+------+ +------+ |
+// +-----+ ||label |label |...|label | |
+// | 1 |-->||value1|value2|...|valueN| |
+// +-----+ |+------+------+ +------+ |
+// | . | |+-----+ |
+// | . | ||value| |
+// | . | |+-----+ |
+// | . | +---------------------------+
+// | . | .
+// | . | .
+// | . | .
+// | . | +---------------------------+
+// | . | |DataPoint M |
+// +-----+ |+------+------+ +------+ |
+// | M |-->||label |label |...|label | |
+// +-----+ ||value1|value2|...|valueN| |
+// |+------+------+ +------+ |
+// |+-----+ |
+// ||value| |
+// |+-----+ |
+// +---------------------------+
+//
+// Each distinct type of DataPoint represents the output of a specific
+// aggregation function, the result of applying the DataPoint's
+// associated function of to one or more measurements.
+//
+// All DataPoint types have three common fields:
+// - Attributes includes key-value pairs associated with the data point
+// - TimeUnixNano is required, set to the end time of the aggregation
+// - StartTimeUnixNano is optional, but strongly encouraged for DataPoints
+// having an AggregationTemporality field, as discussed below.
+//
+// Both TimeUnixNano and StartTimeUnixNano values are expressed as
+// UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+//
+// # TimeUnixNano
+//
+// This field is required, having consistent interpretation across
+// DataPoint types. TimeUnixNano is the moment corresponding to when
+// the data point's aggregate value was captured.
+//
+// Data points with the 0 value for TimeUnixNano SHOULD be rejected
+// by consumers.
+//
+// # StartTimeUnixNano
+//
+// StartTimeUnixNano in general allows detecting when a sequence of
+// observations is unbroken. This field indicates to consumers the
+// start time for points with cumulative and delta
+// AggregationTemporality, and it should be included whenever possible
+// to support correct rate calculation. Although it may be omitted
+// when the start time is truly unknown, setting StartTimeUnixNano is
+// strongly encouraged.
+message Metric {
+ reserved 4, 6, 8;
+
+ // name of the metric.
+ string name = 1;
+
+ // description of the metric, which can be used in documentation.
+ string description = 2;
+
+ // unit in which the metric value is reported. Follows the format
+ // described by https://unitsofmeasure.org/ucum.html.
+ string unit = 3;
+
+ // Data determines the aggregation type (if any) of the metric, what is the
+ // reported value type for the data points, as well as the relatationship to
+ // the time interval over which they are reported.
+ oneof data {
+ Gauge gauge = 5;
+ Sum sum = 7;
+ Histogram histogram = 9;
+ ExponentialHistogram exponential_histogram = 10;
+ Summary summary = 11;
+ }
+
+ // Additional metadata attributes that describe the metric. [Optional].
+ // Attributes are non-identifying.
+ // Consumers SHOULD NOT need to be aware of these attributes.
+ // These attributes MAY be used to encode information allowing
+ // for lossless roundtrip translation to / from another data model.
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue metadata = 12;
+}
+
+// Gauge represents the type of a scalar metric that always exports the
+// "current value" for every data point. It should be used for an "unknown"
+// aggregation.
+//
+// A Gauge does not support different aggregation temporalities. Given the
+// aggregation is unknown, points cannot be combined using the same
+// aggregation, regardless of aggregation temporalities. Therefore,
+// AggregationTemporality is not included. Consequently, this also means
+// "StartTimeUnixNano" is ignored for all data points.
+message Gauge {
+ repeated NumberDataPoint data_points = 1;
+}
+
+// Sum represents the type of a scalar metric that is calculated as a sum of all
+// reported measurements over a time interval.
+message Sum {
+ repeated NumberDataPoint data_points = 1;
+
+ // aggregation_temporality describes if the aggregator reports delta changes
+ // since last report time, or cumulative changes since a fixed start time.
+ AggregationTemporality aggregation_temporality = 2;
+
+ // If "true" means that the sum is monotonic.
+ bool is_monotonic = 3;
+}
+
+// Histogram represents the type of a metric that is calculated by aggregating
+// as a Histogram of all reported measurements over a time interval.
+message Histogram {
+ repeated HistogramDataPoint data_points = 1;
+
+ // aggregation_temporality describes if the aggregator reports delta changes
+ // since last report time, or cumulative changes since a fixed start time.
+ AggregationTemporality aggregation_temporality = 2;
+}
+
+// ExponentialHistogram represents the type of a metric that is calculated by aggregating
+// as a ExponentialHistogram of all reported double measurements over a time interval.
+message ExponentialHistogram {
+ repeated ExponentialHistogramDataPoint data_points = 1;
+
+ // aggregation_temporality describes if the aggregator reports delta changes
+ // since last report time, or cumulative changes since a fixed start time.
+ AggregationTemporality aggregation_temporality = 2;
+}
+
+// Summary metric data are used to convey quantile summaries,
+// a Prometheus (see: https://prometheus.io/docs/concepts/metric_types/#summary)
+// and OpenMetrics (see: https://github.com/prometheus/OpenMetrics/blob/4dbf6075567ab43296eed941037c12951faafb92/protos/prometheus.proto#L45)
+// data type. These data points cannot always be merged in a meaningful way.
+// While they can be useful in some applications, histogram data points are
+// recommended for new applications.
+// Summary metrics do not have an aggregation temporality field. This is
+// because the count and sum fields of a SummaryDataPoint are assumed to be
+// cumulative values.
+message Summary {
+ repeated SummaryDataPoint data_points = 1;
+}
+
+// AggregationTemporality defines how a metric aggregator reports aggregated
+// values. It describes how those values relate to the time interval over
+// which they are aggregated.
+enum AggregationTemporality {
+ // UNSPECIFIED is the default AggregationTemporality, it MUST not be used.
+ AGGREGATION_TEMPORALITY_UNSPECIFIED = 0;
+
+ // DELTA is an AggregationTemporality for a metric aggregator which reports
+ // changes since last report time. Successive metrics contain aggregation of
+ // values from continuous and non-overlapping intervals.
+ //
+ // The values for a DELTA metric are based only on the time interval
+ // associated with one measurement cycle. There is no dependency on
+ // previous measurements like is the case for CUMULATIVE metrics.
+ //
+ // For example, consider a system measuring the number of requests that
+ // it receives and reports the sum of these requests every second as a
+ // DELTA metric:
+ //
+ // 1. The system starts receiving at time=t_0.
+ // 2. A request is received, the system measures 1 request.
+ // 3. A request is received, the system measures 1 request.
+ // 4. A request is received, the system measures 1 request.
+ // 5. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+1 with a value of 3.
+ // 6. A request is received, the system measures 1 request.
+ // 7. A request is received, the system measures 1 request.
+ // 8. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0+1 to
+ // t_0+2 with a value of 2.
+ AGGREGATION_TEMPORALITY_DELTA = 1;
+
+ // CUMULATIVE is an AggregationTemporality for a metric aggregator which
+ // reports changes since a fixed start time. This means that current values
+ // of a CUMULATIVE metric depend on all previous measurements since the
+ // start time. Because of this, the sender is required to retain this state
+ // in some form. If this state is lost or invalidated, the CUMULATIVE metric
+ // values MUST be reset and a new fixed start time following the last
+ // reported measurement time sent MUST be used.
+ //
+ // For example, consider a system measuring the number of requests that
+ // it receives and reports the sum of these requests every second as a
+ // CUMULATIVE metric:
+ //
+ // 1. The system starts receiving at time=t_0.
+ // 2. A request is received, the system measures 1 request.
+ // 3. A request is received, the system measures 1 request.
+ // 4. A request is received, the system measures 1 request.
+ // 5. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+1 with a value of 3.
+ // 6. A request is received, the system measures 1 request.
+ // 7. A request is received, the system measures 1 request.
+ // 8. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+2 with a value of 5.
+ // 9. The system experiences a fault and loses state.
+ // 10. The system recovers and resumes receiving at time=t_1.
+ // 11. A request is received, the system measures 1 request.
+ // 12. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_1 to
+ // t_0+1 with a value of 1.
+ //
+ // Note: Even though, when reporting changes since last report time, using
+ // CUMULATIVE is valid, it is not recommended. This may cause problems for
+ // systems that do not use start_time to determine when the aggregation
+ // value was reset (e.g. Prometheus).
+ AGGREGATION_TEMPORALITY_CUMULATIVE = 2;
+}
+
+// DataPointFlags is defined as a protobuf 'uint32' type and is to be used as a
+// bit-field representing 32 distinct boolean flags. Each flag defined in this
+// enum is a bit-mask. To test the presence of a single flag in the flags of
+// a data point, for example, use an expression like:
+//
+// (point.flags & DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK) == DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK
+//
+enum DataPointFlags {
+ // The zero value for the enum. Should not be used for comparisons.
+ // Instead use bitwise "and" with the appropriate mask as shown above.
+ DATA_POINT_FLAGS_DO_NOT_USE = 0;
+
+ // This DataPoint is valid but has no recorded value. This value
+ // SHOULD be used to reflect explicitly missing data in a series, as
+ // for an equivalent to the Prometheus "staleness marker".
+ DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK = 1;
+
+ // Bits 2-31 are reserved for future use.
+}
+
+// NumberDataPoint is a single data point in a timeseries that describes the
+// time-varying scalar value of a metric.
+message NumberDataPoint {
+ reserved 1;
+
+ // The set of key/value pairs that uniquely identify the timeseries from
+ // where this point belongs. The list may be empty (may contain 0 elements).
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 7;
+
+ // StartTimeUnixNano is optional but strongly encouraged, see the
+ // the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 start_time_unix_nano = 2;
+
+ // TimeUnixNano is required, see the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 time_unix_nano = 3;
+
+ // The value itself. A point is considered invalid when one of the recognized
+ // value fields is not present inside this oneof.
+ oneof value {
+ double as_double = 4;
+ sfixed64 as_int = 6;
+ }
+
+ // (Optional) List of exemplars collected from
+ // measurements that were used to form the data point
+ repeated Exemplar exemplars = 5;
+
+ // Flags that apply to this specific data point. See DataPointFlags
+ // for the available flags and their meaning.
+ uint32 flags = 8;
+}
+
+// HistogramDataPoint is a single data point in a timeseries that describes the
+// time-varying values of a Histogram. A Histogram contains summary statistics
+// for a population of values, it may optionally contain the distribution of
+// those values across a set of buckets.
+//
+// If the histogram contains the distribution of values, then both
+// "explicit_bounds" and "bucket counts" fields must be defined.
+// If the histogram does not contain the distribution of values, then both
+// "explicit_bounds" and "bucket_counts" must be omitted and only "count" and
+// "sum" are known.
+message HistogramDataPoint {
+ reserved 1;
+
+ // The set of key/value pairs that uniquely identify the timeseries from
+ // where this point belongs. The list may be empty (may contain 0 elements).
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 9;
+
+ // StartTimeUnixNano is optional but strongly encouraged, see the
+ // the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 start_time_unix_nano = 2;
+
+ // TimeUnixNano is required, see the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 time_unix_nano = 3;
+
+ // count is the number of values in the population. Must be non-negative. This
+ // value must be equal to the sum of the "count" fields in buckets if a
+ // histogram is provided.
+ fixed64 count = 4;
+
+ // sum of the values in the population. If count is zero then this field
+ // must be zero.
+ //
+ // Note: Sum should only be filled out when measuring non-negative discrete
+ // events, and is assumed to be monotonic over the values of these events.
+ // Negative events *can* be recorded, but sum should not be filled out when
+ // doing so. This is specifically to enforce compatibility w/ OpenMetrics,
+ // see: https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#histogram
+ optional double sum = 5;
+
+ // bucket_counts is an optional field contains the count values of histogram
+ // for each bucket.
+ //
+ // The sum of the bucket_counts must equal the value in the count field.
+ //
+ // The number of elements in bucket_counts array must be by one greater than
+ // the number of elements in explicit_bounds array. The exception to this rule
+ // is when the length of bucket_counts is 0, then the length of explicit_bounds
+ // must also be 0.
+ repeated fixed64 bucket_counts = 6;
+
+ // explicit_bounds specifies buckets with explicitly defined bounds for values.
+ //
+ // The boundaries for bucket at index i are:
+ //
+ // (-infinity, explicit_bounds[i]] for i == 0
+ // (explicit_bounds[i-1], explicit_bounds[i]] for 0 < i < size(explicit_bounds)
+ // (explicit_bounds[i-1], +infinity) for i == size(explicit_bounds)
+ //
+ // The values in the explicit_bounds array must be strictly increasing.
+ //
+ // Histogram buckets are inclusive of their upper boundary, except the last
+ // bucket where the boundary is at infinity. This format is intentionally
+ // compatible with the OpenMetrics histogram definition.
+ //
+ // If bucket_counts length is 0 then explicit_bounds length must also be 0,
+ // otherwise the data point is invalid.
+ repeated double explicit_bounds = 7;
+
+ // (Optional) List of exemplars collected from
+ // measurements that were used to form the data point
+ repeated Exemplar exemplars = 8;
+
+ // Flags that apply to this specific data point. See DataPointFlags
+ // for the available flags and their meaning.
+ uint32 flags = 10;
+
+ // min is the minimum value over (start_time, end_time].
+ optional double min = 11;
+
+ // max is the maximum value over (start_time, end_time].
+ optional double max = 12;
+}
+
+// ExponentialHistogramDataPoint is a single data point in a timeseries that describes the
+// time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains
+// summary statistics for a population of values, it may optionally contain the
+// distribution of those values across a set of buckets.
+//
+message ExponentialHistogramDataPoint {
+ // The set of key/value pairs that uniquely identify the timeseries from
+ // where this point belongs. The list may be empty (may contain 0 elements).
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
+
+ // StartTimeUnixNano is optional but strongly encouraged, see the
+ // the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 start_time_unix_nano = 2;
+
+ // TimeUnixNano is required, see the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 time_unix_nano = 3;
+
+ // count is the number of values in the population. Must be
+ // non-negative. This value must be equal to the sum of the "bucket_counts"
+ // values in the positive and negative Buckets plus the "zero_count" field.
+ fixed64 count = 4;
+
+ // sum of the values in the population. If count is zero then this field
+ // must be zero.
+ //
+ // Note: Sum should only be filled out when measuring non-negative discrete
+ // events, and is assumed to be monotonic over the values of these events.
+ // Negative events *can* be recorded, but sum should not be filled out when
+ // doing so. This is specifically to enforce compatibility w/ OpenMetrics,
+ // see: https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#histogram
+ optional double sum = 5;
+
+ // scale describes the resolution of the histogram. Boundaries are
+ // located at powers of the base, where:
+ //
+ // base = (2^(2^-scale))
+ //
+ // The histogram bucket identified by `index`, a signed integer,
+ // contains values that are greater than (base^index) and
+ // less than or equal to (base^(index+1)).
+ //
+ // The positive and negative ranges of the histogram are expressed
+ // separately. Negative values are mapped by their absolute value
+ // into the negative range using the same scale as the positive range.
+ //
+ // scale is not restricted by the protocol, as the permissible
+ // values depend on the range of the data.
+ sint32 scale = 6;
+
+ // zero_count is the count of values that are either exactly zero or
+ // within the region considered zero by the instrumentation at the
+ // tolerated degree of precision. This bucket stores values that
+ // cannot be expressed using the standard exponential formula as
+ // well as values that have been rounded to zero.
+ //
+ // Implementations MAY consider the zero bucket to have probability
+ // mass equal to (zero_count / count).
+ fixed64 zero_count = 7;
+
+ // positive carries the positive range of exponential bucket counts.
+ Buckets positive = 8;
+
+ // negative carries the negative range of exponential bucket counts.
+ Buckets negative = 9;
+
+ // Buckets are a set of bucket counts, encoded in a contiguous array
+ // of counts.
+ message Buckets {
+ // Offset is the bucket index of the first entry in the bucket_counts array.
+ //
+ // Note: This uses a varint encoding as a simple form of compression.
+ sint32 offset = 1;
+
+ // bucket_counts is an array of count values, where bucket_counts[i] carries
+ // the count of the bucket at index (offset+i). bucket_counts[i] is the count
+ // of values greater than base^(offset+i) and less than or equal to
+ // base^(offset+i+1).
+ //
+ // Note: By contrast, the explicit HistogramDataPoint uses
+ // fixed64. This field is expected to have many buckets,
+ // especially zeros, so uint64 has been selected to ensure
+ // varint encoding.
+ repeated uint64 bucket_counts = 2;
+ }
+
+ // Flags that apply to this specific data point. See DataPointFlags
+ // for the available flags and their meaning.
+ uint32 flags = 10;
+
+ // (Optional) List of exemplars collected from
+ // measurements that were used to form the data point
+ repeated Exemplar exemplars = 11;
+
+ // min is the minimum value over (start_time, end_time].
+ optional double min = 12;
+
+ // max is the maximum value over (start_time, end_time].
+ optional double max = 13;
+
+ // ZeroThreshold may be optionally set to convey the width of the zero
+ // region. Where the zero region is defined as the closed interval
+ // [-ZeroThreshold, ZeroThreshold].
+ // When ZeroThreshold is 0, zero count bucket stores values that cannot be
+ // expressed using the standard exponential formula as well as values that
+ // have been rounded to zero.
+ double zero_threshold = 14;
+}
+
+// SummaryDataPoint is a single data point in a timeseries that describes the
+// time-varying values of a Summary metric. The count and sum fields represent
+// cumulative values.
+message SummaryDataPoint {
+ reserved 1;
+
+ // The set of key/value pairs that uniquely identify the timeseries from
+ // where this point belongs. The list may be empty (may contain 0 elements).
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 7;
+
+ // StartTimeUnixNano is optional but strongly encouraged, see the
+ // the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 start_time_unix_nano = 2;
+
+ // TimeUnixNano is required, see the detailed comments above Metric.
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 time_unix_nano = 3;
+
+ // count is the number of values in the population. Must be non-negative.
+ fixed64 count = 4;
+
+ // sum of the values in the population. If count is zero then this field
+ // must be zero.
+ //
+ // Note: Sum should only be filled out when measuring non-negative discrete
+ // events, and is assumed to be monotonic over the values of these events.
+ // Negative events *can* be recorded, but sum should not be filled out when
+ // doing so. This is specifically to enforce compatibility w/ OpenMetrics,
+ // see: https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#summary
+ double sum = 5;
+
+ // Represents the value at a given quantile of a distribution.
+ //
+ // To record Min and Max values following conventions are used:
+ // - The 1.0 quantile is equivalent to the maximum value observed.
+ // - The 0.0 quantile is equivalent to the minimum value observed.
+ //
+ // See the following issue for more context:
+ // https://github.com/open-telemetry/opentelemetry-proto/issues/125
+ message ValueAtQuantile {
+ // The quantile of a distribution. Must be in the interval
+ // [0.0, 1.0].
+ double quantile = 1;
+
+ // The value at the given quantile of a distribution.
+ //
+ // Quantile values must NOT be negative.
+ double value = 2;
+ }
+
+ // (Optional) list of values at different quantiles of the distribution calculated
+ // from the current snapshot. The quantiles must be strictly increasing.
+ repeated ValueAtQuantile quantile_values = 6;
+
+ // Flags that apply to this specific data point. See DataPointFlags
+ // for the available flags and their meaning.
+ uint32 flags = 8;
+}
+
+// A representation of an exemplar, which is a sample input measurement.
+// Exemplars also hold information about the environment when the measurement
+// was recorded, for example the span and trace ID of the active span when the
+// exemplar was recorded.
+message Exemplar {
+ reserved 1;
+
+ // The set of key/value pairs that were filtered out by the aggregator, but
+ // recorded alongside the original measurement. Only key/value pairs that were
+ // filtered out by the aggregator should be included
+ repeated opentelemetry.proto.common.v1.KeyValue filtered_attributes = 7;
+
+ // time_unix_nano is the exact time when this exemplar was recorded
+ //
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January
+ // 1970.
+ fixed64 time_unix_nano = 2;
+
+ // The value of the measurement that was recorded. An exemplar is
+ // considered invalid when one of the recognized value fields is not present
+ // inside this oneof.
+ oneof value {
+ double as_double = 3;
+ sfixed64 as_int = 6;
+ }
+
+ // (Optional) Span ID of the exemplar trace.
+ // span_id may be missing if the measurement is not recorded inside a trace
+ // or if the trace is not sampled.
+ bytes span_id = 4;
+
+ // (Optional) Trace ID of the exemplar trace.
+ // trace_id may be missing if the measurement is not recorded inside a trace
+ // or if the trace is not sampled.
+ bytes trace_id = 5;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/profiles/v1development/profiles.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/profiles/v1development/profiles.proto
new file mode 100644
index 00000000..f3821d0a
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/profiles/v1development/profiles.proto
@@ -0,0 +1,474 @@
+// Copyright 2023, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file includes work covered by the following copyright and permission notices:
+//
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.profiles.v1development;
+
+import "opentelemetry/proto/common/v1/common.proto";
+import "opentelemetry/proto/resource/v1/resource.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Profiles.V1Development";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.profiles.v1development";
+option java_outer_classname = "ProfilesProto";
+option go_package = "go.opentelemetry.io/proto/otlp/profiles/v1development";
+
+// Relationships Diagram
+//
+// ┌──────────────────┐ LEGEND
+// │ ProfilesData │
+// └──────────────────┘ ─────▶ embedded
+// │
+// │ 1-n ─────▷ referenced by index
+// ▼
+// ┌──────────────────┐
+// │ ResourceProfiles │
+// └──────────────────┘
+// │
+// │ 1-n
+// ▼
+// ┌──────────────────┐
+// │ ScopeProfiles │
+// └──────────────────┘
+// │
+// │ 1-1
+// ▼
+// ┌──────────────────┐
+// │ Profile │
+// └──────────────────┘
+// │ n-1
+// │ 1-n ┌───────────────────────────────────────┐
+// ▼ │ ▽
+// ┌──────────────────┐ 1-n ┌──────────────┐ ┌──────────┐
+// │ Sample │ ──────▷ │ KeyValue │ │ Link │
+// └──────────────────┘ └──────────────┘ └──────────┘
+// │ 1-n △ △
+// │ 1-n ┌─────────────────┘ │ 1-n
+// ▽ │ │
+// ┌──────────────────┐ n-1 ┌──────────────┐
+// │ Location │ ──────▷ │ Mapping │
+// └──────────────────┘ └──────────────┘
+// │
+// │ 1-n
+// ▼
+// ┌──────────────────┐
+// │ Line │
+// └──────────────────┘
+// │
+// │ 1-1
+// ▽
+// ┌──────────────────┐
+// │ Function │
+// └──────────────────┘
+//
+
+// ProfilesData represents the profiles data that can be stored in persistent storage,
+// OR can be embedded by other protocols that transfer OTLP profiles data but do not
+// implement the OTLP protocol.
+//
+// The main difference between this message and collector protocol is that
+// in this message there will not be any "control" or "metadata" specific to
+// OTLP protocol.
+//
+// When new fields are added into this message, the OTLP request MUST be updated
+// as well.
+message ProfilesData {
+ // An array of ResourceProfiles.
+ // For data coming from a single resource this array will typically contain
+ // one element. Intermediary nodes that receive data from multiple origins
+ // typically batch the data before forwarding further and in that case this
+ // array will contain multiple elements.
+ repeated ResourceProfiles resource_profiles = 1;
+}
+
+
+// A collection of ScopeProfiles from a Resource.
+message ResourceProfiles {
+ reserved 1000;
+
+ // The resource for the profiles in this message.
+ // If this field is not set then no resource info is known.
+ opentelemetry.proto.resource.v1.Resource resource = 1;
+
+ // A list of ScopeProfiles that originate from a resource.
+ repeated ScopeProfiles scope_profiles = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the resource data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to the data in the "resource" field. It does not apply
+ // to the data in the "scope_profiles" field which have their own schema_url field.
+ string schema_url = 3;
+}
+
+// A collection of Profiles produced by an InstrumentationScope.
+message ScopeProfiles {
+ // The instrumentation scope information for the profiles in this message.
+ // Semantically when InstrumentationScope isn't set, it is equivalent with
+ // an empty instrumentation scope name (unknown).
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
+
+ // A list of Profiles that originate from an instrumentation scope.
+ repeated Profile profiles = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the profile data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to all profiles in the "profiles" field.
+ string schema_url = 3;
+}
+
+// Profile is a common stacktrace profile format.
+//
+// Measurements represented with this format should follow the
+// following conventions:
+//
+// - Consumers should treat unset optional fields as if they had been
+// set with their default value.
+//
+// - When possible, measurements should be stored in "unsampled" form
+// that is most useful to humans. There should be enough
+// information present to determine the original sampled values.
+//
+// - On-disk, the serialized proto must be gzip-compressed.
+//
+// - The profile is represented as a set of samples, where each sample
+// references a sequence of locations, and where each location belongs
+// to a mapping.
+// - There is a N->1 relationship from sample.location_id entries to
+// locations. For every sample.location_id entry there must be a
+// unique Location with that index.
+// - There is an optional N->1 relationship from locations to
+// mappings. For every nonzero Location.mapping_id there must be a
+// unique Mapping with that index.
+
+// Represents a complete profile, including sample types, samples,
+// mappings to binaries, locations, functions, string table, and additional metadata.
+// It modifies and annotates pprof Profile with OpenTelemetry specific fields.
+//
+// Note that whilst fields in this message retain the name and field id from pprof in most cases
+// for ease of understanding data migration, it is not intended that pprof:Profile and
+// OpenTelemetry:Profile encoding be wire compatible.
+message Profile {
+
+ // A description of the samples associated with each Sample.value.
+ // For a cpu profile this might be:
+ // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]]
+ // For a heap profile, this might be:
+ // [["allocations","count"], ["space","bytes"]],
+ // If one of the values represents the number of events represented
+ // by the sample, by convention it should be at index 0 and use
+ // sample_type.unit == "count".
+ repeated ValueType sample_type = 1;
+ // The set of samples recorded in this profile.
+ repeated Sample sample = 2;
+ // Mapping from address ranges to the image/binary/library mapped
+ // into that address range. mapping[0] will be the main binary.
+ // If multiple binaries contribute to the Profile and no main
+ // binary can be identified, mapping[0] has no special meaning.
+ repeated Mapping mapping_table = 3;
+ // Locations referenced by samples via location_indices.
+ repeated Location location_table = 4;
+ // Array of locations referenced by samples.
+ repeated int32 location_indices = 5;
+ // Functions referenced by locations.
+ repeated Function function_table = 6;
+ // Lookup table for attributes.
+ repeated opentelemetry.proto.common.v1.KeyValue attribute_table = 7;
+ // Represents a mapping between Attribute Keys and Units.
+ repeated AttributeUnit attribute_units = 8;
+ // Lookup table for links.
+ repeated Link link_table = 9;
+ // A common table for strings referenced by various messages.
+ // string_table[0] must always be "".
+ repeated string string_table = 10;
+
+ // The following fields 9-14 are informational, do not affect
+ // interpretation of results.
+
+ // Time of collection (UTC) represented as nanoseconds past the epoch.
+ int64 time_nanos = 11;
+ // Duration of the profile, if a duration makes sense.
+ int64 duration_nanos = 12;
+ // The kind of events between sampled occurrences.
+ // e.g [ "cpu","cycles" ] or [ "heap","bytes" ]
+ ValueType period_type = 13;
+ // The number of events between sampled occurrences.
+ int64 period = 14;
+ // Free-form text associated with the profile. The text is displayed as is
+ // to the user by the tools that read profiles (e.g. by pprof). This field
+ // should not be used to store any machine-readable information, it is only
+ // for human-friendly content. The profile must stay functional if this field
+ // is cleaned.
+ repeated int32 comment_strindices = 15; // Indices into string table.
+ // Index into the sample_type array to the default sample type.
+ int32 default_sample_type_index = 16;
+
+
+ // A globally unique identifier for a profile. The ID is a 16-byte array. An ID with
+ // all zeroes is considered invalid.
+ //
+ // This field is required.
+ bytes profile_id = 17;
+
+ // dropped_attributes_count is the number of attributes that were discarded. Attributes
+ // can be discarded because their keys are too long or because there are too many
+ // attributes. If this value is 0, then no attributes were dropped.
+ uint32 dropped_attributes_count = 19;
+
+ // Specifies format of the original payload. Common values are defined in semantic conventions. [required if original_payload is present]
+ string original_payload_format = 20;
+
+ // Original payload can be stored in this field. This can be useful for users who want to get the original payload.
+ // Formats such as JFR are highly extensible and can contain more information than what is defined in this spec.
+ // Inclusion of original payload should be configurable by the user. Default behavior should be to not include the original payload.
+ // If the original payload is in pprof format, it SHOULD not be included in this field.
+ // The field is optional, however if it is present then equivalent converted data should be populated in other fields
+ // of this message as far as is practicable.
+ bytes original_payload = 21;
+
+ // References to attributes in attribute_table. [optional]
+ // It is a collection of key/value pairs. Note, global attributes
+ // like server name can be set using the resource API. Examples of attributes:
+ //
+ // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
+ // "/http/server_latency": 300
+ // "abc.com/myattribute": true
+ // "abc.com/score": 10.239
+ //
+ // The OpenTelemetry API specification further restricts the allowed value types:
+ // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated int32 attribute_indices = 22;
+}
+
+// Represents a mapping between Attribute Keys and Units.
+message AttributeUnit {
+ // Index into string table.
+ int32 attribute_key_strindex = 1;
+ // Index into string table.
+ int32 unit_strindex = 2;
+}
+
+// A pointer from a profile Sample to a trace Span.
+// Connects a profile sample to a trace span, identified by unique trace and span IDs.
+message Link {
+ // A unique identifier of a trace that this linked span is part of. The ID is a
+ // 16-byte array.
+ bytes trace_id = 1;
+
+ // A unique identifier for the linked span. The ID is an 8-byte array.
+ bytes span_id = 2;
+}
+
+// Specifies the method of aggregating metric values, either DELTA (change since last report)
+// or CUMULATIVE (total since a fixed start time).
+enum AggregationTemporality {
+ /* UNSPECIFIED is the default AggregationTemporality, it MUST not be used. */
+ AGGREGATION_TEMPORALITY_UNSPECIFIED = 0;
+
+ /** DELTA is an AggregationTemporality for a profiler which reports
+ changes since last report time. Successive metrics contain aggregation of
+ values from continuous and non-overlapping intervals.
+
+ The values for a DELTA metric are based only on the time interval
+ associated with one measurement cycle. There is no dependency on
+ previous measurements like is the case for CUMULATIVE metrics.
+
+ For example, consider a system measuring the number of requests that
+ it receives and reports the sum of these requests every second as a
+ DELTA metric:
+
+ 1. The system starts receiving at time=t_0.
+ 2. A request is received, the system measures 1 request.
+ 3. A request is received, the system measures 1 request.
+ 4. A request is received, the system measures 1 request.
+ 5. The 1 second collection cycle ends. A metric is exported for the
+ number of requests received over the interval of time t_0 to
+ t_0+1 with a value of 3.
+ 6. A request is received, the system measures 1 request.
+ 7. A request is received, the system measures 1 request.
+ 8. The 1 second collection cycle ends. A metric is exported for the
+ number of requests received over the interval of time t_0+1 to
+ t_0+2 with a value of 2. */
+ AGGREGATION_TEMPORALITY_DELTA = 1;
+
+ /** CUMULATIVE is an AggregationTemporality for a profiler which
+ reports changes since a fixed start time. This means that current values
+ of a CUMULATIVE metric depend on all previous measurements since the
+ start time. Because of this, the sender is required to retain this state
+ in some form. If this state is lost or invalidated, the CUMULATIVE metric
+ values MUST be reset and a new fixed start time following the last
+ reported measurement time sent MUST be used.
+
+ For example, consider a system measuring the number of requests that
+ it receives and reports the sum of these requests every second as a
+ CUMULATIVE metric:
+
+ 1. The system starts receiving at time=t_0.
+ 2. A request is received, the system measures 1 request.
+ 3. A request is received, the system measures 1 request.
+ 4. A request is received, the system measures 1 request.
+ 5. The 1 second collection cycle ends. A metric is exported for the
+ number of requests received over the interval of time t_0 to
+ t_0+1 with a value of 3.
+ 6. A request is received, the system measures 1 request.
+ 7. A request is received, the system measures 1 request.
+ 8. The 1 second collection cycle ends. A metric is exported for the
+ number of requests received over the interval of time t_0 to
+ t_0+2 with a value of 5.
+ 9. The system experiences a fault and loses state.
+ 10. The system recovers and resumes receiving at time=t_1.
+ 11. A request is received, the system measures 1 request.
+ 12. The 1 second collection cycle ends. A metric is exported for the
+ number of requests received over the interval of time t_1 to
+ t_1+1 with a value of 1.
+
+ Note: Even though, when reporting changes since last report time, using
+ CUMULATIVE is valid, it is not recommended. */
+ AGGREGATION_TEMPORALITY_CUMULATIVE = 2;
+}
+
+// ValueType describes the type and units of a value, with an optional aggregation temporality.
+message ValueType {
+ int32 type_strindex = 1; // Index into string table.
+ int32 unit_strindex = 2; // Index into string table.
+
+ AggregationTemporality aggregation_temporality = 3;
+}
+
+// Each Sample records values encountered in some program
+// context. The program context is typically a stack trace, perhaps
+// augmented with auxiliary information like the thread-id, some
+// indicator of a higher level request being handled etc.
+message Sample {
+ // locations_start_index along with locations_length refers to to a slice of locations in Profile.location_indices.
+ int32 locations_start_index = 1;
+ // locations_length along with locations_start_index refers to a slice of locations in Profile.location_indices.
+ // Supersedes location_index.
+ int32 locations_length = 2;
+ // The type and unit of each value is defined by the corresponding
+ // entry in Profile.sample_type. All samples must have the same
+ // number of values, the same as the length of Profile.sample_type.
+ // When aggregating multiple samples into a single sample, the
+ // result has a list of values that is the element-wise sum of the
+ // lists of the originals.
+ repeated int64 value = 3;
+ // References to attributes in Profile.attribute_table. [optional]
+ repeated int32 attribute_indices = 4;
+
+ // Reference to link in Profile.link_table. [optional]
+ optional int32 link_index = 5;
+
+ // Timestamps associated with Sample represented in nanoseconds. These timestamps are expected
+ // to fall within the Profile's time range. [optional]
+ repeated uint64 timestamps_unix_nano = 6;
+}
+
+// Describes the mapping of a binary in memory, including its address range,
+// file offset, and metadata like build ID
+message Mapping {
+ // Address at which the binary (or DLL) is loaded into memory.
+ uint64 memory_start = 1;
+ // The limit of the address range occupied by this mapping.
+ uint64 memory_limit = 2;
+ // Offset in the binary that corresponds to the first mapped address.
+ uint64 file_offset = 3;
+ // The object this entry is loaded from. This can be a filename on
+ // disk for the main binary and shared libraries, or virtual
+ // abstractions like "[vdso]".
+ int32 filename_strindex = 4; // Index into string table
+ // References to attributes in Profile.attribute_table. [optional]
+ repeated int32 attribute_indices = 5;
+ // The following fields indicate the resolution of symbolic info.
+ bool has_functions = 6;
+ bool has_filenames = 7;
+ bool has_line_numbers = 8;
+ bool has_inline_frames = 9;
+}
+
+// Describes function and line table debug information.
+message Location {
+ // Reference to mapping in Profile.mapping_table.
+ // It can be unset if the mapping is unknown or not applicable for
+ // this profile type.
+ optional int32 mapping_index = 1;
+ // The instruction address for this location, if available. It
+ // should be within [Mapping.memory_start...Mapping.memory_limit]
+ // for the corresponding mapping. A non-leaf address may be in the
+ // middle of a call instruction. It is up to display tools to find
+ // the beginning of the instruction if necessary.
+ uint64 address = 2;
+ // Multiple line indicates this location has inlined functions,
+ // where the last entry represents the caller into which the
+ // preceding entries were inlined.
+ //
+ // E.g., if memcpy() is inlined into printf:
+ // line[0].function_name == "memcpy"
+ // line[1].function_name == "printf"
+ repeated Line line = 3;
+ // Provides an indication that multiple symbols map to this location's
+ // address, for example due to identical code folding by the linker. In that
+ // case the line information above represents one of the multiple
+ // symbols. This field must be recomputed when the symbolization state of the
+ // profile changes.
+ bool is_folded = 4;
+
+ // References to attributes in Profile.attribute_table. [optional]
+ repeated int32 attribute_indices = 5;
+}
+
+// Details a specific line in a source code, linked to a function.
+message Line {
+ // Reference to function in Profile.function_table.
+ int32 function_index = 1;
+ // Line number in source code.
+ int64 line = 2;
+ // Column number in source code.
+ int64 column = 3;
+}
+
+// Describes a function, including its human-readable name, system name,
+// source file, and starting line number in the source.
+message Function {
+ // Name of the function, in human-readable form if available.
+ int32 name_strindex = 1; // Index into string table
+ // Name of the function, as identified by the system.
+ // For instance, it can be a C++ mangled name.
+ int32 system_name_strindex = 2; // Index into string table
+ // Source file containing the function.
+ int32 filename_strindex = 3; // Index into string table
+ // Line number in source file.
+ int64 start_line = 4;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/resource/v1/resource.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/resource/v1/resource.proto
new file mode 100644
index 00000000..6637560b
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/resource/v1/resource.proto
@@ -0,0 +1,37 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.resource.v1;
+
+import "opentelemetry/proto/common/v1/common.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Resource.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.resource.v1";
+option java_outer_classname = "ResourceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/resource/v1";
+
+// Resource information.
+message Resource {
+ // Set of attributes that describe the resource.
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
+
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0, then
+ // no attributes were dropped.
+ uint32 dropped_attributes_count = 2;
+}
diff --git a/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/trace/v1/trace.proto b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/trace/v1/trace.proto
new file mode 100644
index 00000000..24442853
--- /dev/null
+++ b/test/WireMock.Net.Tests/Grpc/ot/opentelemetry/proto/trace/v1/trace.proto
@@ -0,0 +1,357 @@
+// Copyright 2019, OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package opentelemetry.proto.trace.v1;
+
+import "opentelemetry/proto/common/v1/common.proto";
+import "opentelemetry/proto/resource/v1/resource.proto";
+
+option csharp_namespace = "OpenTelemetry.Proto.Trace.V1";
+option java_multiple_files = true;
+option java_package = "io.opentelemetry.proto.trace.v1";
+option java_outer_classname = "TraceProto";
+option go_package = "go.opentelemetry.io/proto/otlp/trace/v1";
+
+// TracesData represents the traces data that can be stored in a persistent storage,
+// OR can be embedded by other protocols that transfer OTLP traces data but do
+// not implement the OTLP protocol.
+//
+// The main difference between this message and collector protocol is that
+// in this message there will not be any "control" or "metadata" specific to
+// OTLP protocol.
+//
+// When new fields are added into this message, the OTLP request MUST be updated
+// as well.
+message TracesData {
+ // An array of ResourceSpans.
+ // For data coming from a single resource this array will typically contain
+ // one element. Intermediary nodes that receive data from multiple origins
+ // typically batch the data before forwarding further and in that case this
+ // array will contain multiple elements.
+ repeated ResourceSpans resource_spans = 1;
+}
+
+// A collection of ScopeSpans from a Resource.
+message ResourceSpans {
+ reserved 1000;
+
+ // The resource for the spans in this message.
+ // If this field is not set then no resource info is known.
+ opentelemetry.proto.resource.v1.Resource resource = 1;
+
+ // A list of ScopeSpans that originate from a resource.
+ repeated ScopeSpans scope_spans = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the resource data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to the data in the "resource" field. It does not apply
+ // to the data in the "scope_spans" field which have their own schema_url field.
+ string schema_url = 3;
+}
+
+// A collection of Spans produced by an InstrumentationScope.
+message ScopeSpans {
+ // The instrumentation scope information for the spans in this message.
+ // Semantically when InstrumentationScope isn't set, it is equivalent with
+ // an empty instrumentation scope name (unknown).
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
+
+ // A list of Spans that originate from an instrumentation scope.
+ repeated Span spans = 2;
+
+ // The Schema URL, if known. This is the identifier of the Schema that the span data
+ // is recorded in. Notably, the last part of the URL path is the version number of the
+ // schema: http[s]://server[:port]/path/. To learn more about Schema URL see
+ // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url
+ // This schema_url applies to all spans and span events in the "spans" field.
+ string schema_url = 3;
+}
+
+// A Span represents a single operation performed by a single component of the system.
+//
+// The next available field id is 17.
+message Span {
+ // A unique identifier for a trace. All spans from the same trace share
+ // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR
+ // of length other than 16 bytes is considered invalid (empty string in OTLP/JSON
+ // is zero-length and thus is also invalid).
+ //
+ // This field is required.
+ bytes trace_id = 1;
+
+ // A unique identifier for a span within a trace, assigned when the span
+ // is created. The ID is an 8-byte array. An ID with all zeroes OR of length
+ // other than 8 bytes is considered invalid (empty string in OTLP/JSON
+ // is zero-length and thus is also invalid).
+ //
+ // This field is required.
+ bytes span_id = 2;
+
+ // trace_state conveys information about request position in multiple distributed tracing graphs.
+ // It is a trace_state in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header
+ // See also https://github.com/w3c/distributed-tracing for more details about this field.
+ string trace_state = 3;
+
+ // The `span_id` of this span's parent span. If this is a root span, then this
+ // field must be empty. The ID is an 8-byte array.
+ bytes parent_span_id = 4;
+
+ // Flags, a bit field.
+ //
+ // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace
+ // Context specification. To read the 8-bit W3C trace flag, use
+ // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`.
+ //
+ // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions.
+ //
+ // Bits 8 and 9 represent the 3 states of whether a span's parent
+ // is remote. The states are (unknown, is not remote, is remote).
+ // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`.
+ // To read whether the span is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`.
+ //
+ // When creating span messages, if the message is logically forwarded from another source
+ // with an equivalent flags fields (i.e., usually another OTLP span message), the field SHOULD
+ // be copied as-is. If creating from a source that does not have an equivalent flags field
+ // (such as a runtime representation of an OpenTelemetry span), the high 22 bits MUST
+ // be set to zero.
+ // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero.
+ //
+ // [Optional].
+ fixed32 flags = 16;
+
+ // A description of the span's operation.
+ //
+ // For example, the name can be a qualified method name or a file name
+ // and a line number where the operation is called. A best practice is to use
+ // the same display name at the same call point in an application.
+ // This makes it easier to correlate spans in different traces.
+ //
+ // This field is semantically required to be set to non-empty string.
+ // Empty value is equivalent to an unknown span name.
+ //
+ // This field is required.
+ string name = 5;
+
+ // SpanKind is the type of span. Can be used to specify additional relationships between spans
+ // in addition to a parent/child relationship.
+ enum SpanKind {
+ // Unspecified. Do NOT use as default.
+ // Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED.
+ SPAN_KIND_UNSPECIFIED = 0;
+
+ // Indicates that the span represents an internal operation within an application,
+ // as opposed to an operation happening at the boundaries. Default value.
+ SPAN_KIND_INTERNAL = 1;
+
+ // Indicates that the span covers server-side handling of an RPC or other
+ // remote network request.
+ SPAN_KIND_SERVER = 2;
+
+ // Indicates that the span describes a request to some remote service.
+ SPAN_KIND_CLIENT = 3;
+
+ // Indicates that the span describes a producer sending a message to a broker.
+ // Unlike CLIENT and SERVER, there is often no direct critical path latency relationship
+ // between producer and consumer spans. A PRODUCER span ends when the message was accepted
+ // by the broker while the logical processing of the message might span a much longer time.
+ SPAN_KIND_PRODUCER = 4;
+
+ // Indicates that the span describes consumer receiving a message from a broker.
+ // Like the PRODUCER kind, there is often no direct critical path latency relationship
+ // between producer and consumer spans.
+ SPAN_KIND_CONSUMER = 5;
+ }
+
+ // Distinguishes between spans generated in a particular context. For example,
+ // two spans with the same name may be distinguished using `CLIENT` (caller)
+ // and `SERVER` (callee) to identify queueing latency associated with the span.
+ SpanKind kind = 6;
+
+ // start_time_unix_nano is the start time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution starts. On the server side, this
+ // is the time when the server's application handler starts running.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // This field is semantically required and it is expected that end_time >= start_time.
+ fixed64 start_time_unix_nano = 7;
+
+ // end_time_unix_nano is the end time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution ends. On the server side, this
+ // is the time when the server application handler stops running.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // This field is semantically required and it is expected that end_time >= start_time.
+ fixed64 end_time_unix_nano = 8;
+
+ // attributes is a collection of key/value pairs. Note, global attributes
+ // like server name can be set using the resource API. Examples of attributes:
+ //
+ // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
+ // "/http/server_latency": 300
+ // "example.com/myattribute": true
+ // "example.com/score": 10.239
+ //
+ // The OpenTelemetry API specification further restricts the allowed value types:
+ // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 9;
+
+ // dropped_attributes_count is the number of attributes that were discarded. Attributes
+ // can be discarded because their keys are too long or because there are too many
+ // attributes. If this value is 0, then no attributes were dropped.
+ uint32 dropped_attributes_count = 10;
+
+ // Event is a time-stamped annotation of the span, consisting of user-supplied
+ // text description and key-value pairs.
+ message Event {
+ // time_unix_nano is the time the event occurred.
+ fixed64 time_unix_nano = 1;
+
+ // name of the event.
+ // This field is semantically required to be set to non-empty string.
+ string name = 2;
+
+ // attributes is a collection of attribute key/value pairs on the event.
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 3;
+
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0,
+ // then no attributes were dropped.
+ uint32 dropped_attributes_count = 4;
+ }
+
+ // events is a collection of Event items.
+ repeated Event events = 11;
+
+ // dropped_events_count is the number of dropped events. If the value is 0, then no
+ // events were dropped.
+ uint32 dropped_events_count = 12;
+
+ // A pointer from the current span to another span in the same trace or in a
+ // different trace. For example, this can be used in batching operations,
+ // where a single batch handler processes multiple requests from different
+ // traces or when the handler receives a request from a different project.
+ message Link {
+ // A unique identifier of a trace that this linked span is part of. The ID is a
+ // 16-byte array.
+ bytes trace_id = 1;
+
+ // A unique identifier for the linked span. The ID is an 8-byte array.
+ bytes span_id = 2;
+
+ // The trace_state associated with the link.
+ string trace_state = 3;
+
+ // attributes is a collection of attribute key/value pairs on the link.
+ // Attribute keys MUST be unique (it is not allowed to have more than one
+ // attribute with the same key).
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 4;
+
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0,
+ // then no attributes were dropped.
+ uint32 dropped_attributes_count = 5;
+
+ // Flags, a bit field.
+ //
+ // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace
+ // Context specification. To read the 8-bit W3C trace flag, use
+ // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`.
+ //
+ // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions.
+ //
+ // Bits 8 and 9 represent the 3 states of whether the link is remote.
+ // The states are (unknown, is not remote, is remote).
+ // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`.
+ // To read whether the link is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`.
+ //
+ // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero.
+ // When creating new spans, bits 10-31 (most-significant 22-bits) MUST be zero.
+ //
+ // [Optional].
+ fixed32 flags = 6;
+ }
+
+ // links is a collection of Links, which are references from this span to a span
+ // in the same or different trace.
+ repeated Link links = 13;
+
+ // dropped_links_count is the number of dropped links after the maximum size was
+ // enforced. If this value is 0, then no links were dropped.
+ uint32 dropped_links_count = 14;
+
+ // An optional final status for this span. Semantically when Status isn't set, it means
+ // span's status code is unset, i.e. assume STATUS_CODE_UNSET (code = 0).
+ Status status = 15;
+}
+
+// The Status type defines a logical error model that is suitable for different
+// programming environments, including REST APIs and RPC APIs.
+message Status {
+ reserved 1;
+
+ // A developer-facing human readable error message.
+ string message = 2;
+
+ // For the semantics of status codes see
+ // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status
+ enum StatusCode {
+ // The default status.
+ STATUS_CODE_UNSET = 0;
+ // The Span has been validated by an Application developer or Operator to
+ // have completed successfully.
+ STATUS_CODE_OK = 1;
+ // The Span contains an error.
+ STATUS_CODE_ERROR = 2;
+ };
+
+ // The status code.
+ StatusCode code = 3;
+}
+
+// SpanFlags represents constants used to interpret the
+// Span.flags field, which is protobuf 'fixed32' type and is to
+// be used as bit-fields. Each non-zero value defined in this enum is
+// a bit-mask. To extract the bit-field, for example, use an
+// expression like:
+//
+// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK)
+//
+// See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions.
+//
+// Note that Span flags were introduced in version 1.1 of the
+// OpenTelemetry protocol. Older Span producers do not set this
+// field, consequently consumers should not rely on the absence of a
+// particular flag bit to indicate the presence of a particular feature.
+enum SpanFlags {
+ // The zero value for the enum. Should not be used for comparisons.
+ // Instead use bitwise "and" with the appropriate mask as shown above.
+ SPAN_FLAGS_DO_NOT_USE = 0;
+
+ // Bits 0-7 are used for trace flags.
+ SPAN_FLAGS_TRACE_FLAGS_MASK = 0x000000FF;
+
+ // Bits 8 and 9 are used to indicate that the parent span or link span is remote.
+ // Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known.
+ // Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote.
+ SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK = 0x00000100;
+ SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK = 0x00000200;
+
+ // Bits 10-31 are reserved for future use.
+}
diff --git a/test/WireMock.Net.Tests/OpenApiParser/PathUtilsTests.cs b/test/WireMock.Net.Tests/OpenApiParser/PathUtilsTests.cs
new file mode 100644
index 00000000..64a853da
--- /dev/null
+++ b/test/WireMock.Net.Tests/OpenApiParser/PathUtilsTests.cs
@@ -0,0 +1,40 @@
+// Copyright © WireMock.Net
+
+#if !(NET452 || NET461 || NETCOREAPP3_1)
+using FluentAssertions;
+using WireMock.Net.OpenApiParser.Utils;
+using Xunit;
+
+namespace WireMock.Net.Tests.OpenApiParser;
+
+public class PathUtilsTests
+{
+ [Theory]
+ [InlineData(new string[] { }, "")]
+ [InlineData(new[] { "path1" }, "path1")]
+ [InlineData(new[] { "/path1" }, "/path1")]
+ [InlineData(new[] { "/path1/" }, "/path1")]
+ public void Combine_ShouldReturnCombinedPathTest1(string[] paths, string expected)
+ {
+ // Act
+ var result = PathUtils.Combine(paths);
+
+ // Assert
+ result.Should().Be(expected);
+ }
+
+ [Theory]
+ [InlineData("/path1", "path2")]
+ [InlineData("/path1/", "path2")]
+ [InlineData("/path1", "/path2")]
+ [InlineData("/path1", "path2/")]
+ public void Combine_ShouldReturnCombinedPathTest2(params string[] paths)
+ {
+ // Act
+ var result = PathUtils.Combine(paths);
+
+ // Assert
+ result.Should().Be("/path1/path2");
+ }
+}
+#endif
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.FromText_ShouldReturnMappings.verified.txt b/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.FromText_ShouldReturnMappings.verified.txt
index 6733a459..382d8455 100644
--- a/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.FromText_ShouldReturnMappings.verified.txt
+++ b/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.FromText_ShouldReturnMappings.verified.txt
@@ -334,7 +334,7 @@
"processingTerminalId": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED",
@@ -1787,7 +1787,7 @@
"processingTerminalId": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED"
@@ -2714,7 +2714,7 @@
"processingTerminalId": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED",
@@ -2863,7 +2863,7 @@
"processingTerminalId": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED"
@@ -6893,7 +6893,7 @@
"operator": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED",
@@ -7093,7 +7093,7 @@
"offlineProcessing": {
"operation": "offlineDecline",
"approvalCode": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00"
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00"
},
"autoCapture": true,
"processAsSale": true
@@ -11349,7 +11349,7 @@
{
"op": "replace",
"path": "/a/b/c",
- "value": "42"
+ "value": 420
},
{
"op": "move",
@@ -11827,7 +11827,7 @@
{
"op": "replace",
"path": "/a/b/c",
- "value": "42"
+ "value": 420
},
{
"op": "move",
@@ -12541,7 +12541,7 @@
{
"op": "replace",
"path": "/a/b/c",
- "value": "42"
+ "value": 420
},
{
"op": "move",
@@ -12986,7 +12986,7 @@
"operator": "example-string",
"order": {
"orderId": "example-string",
- "dateTime": "2024-06-19T12:34:56.000+00:00",
+ "dateTime": "2024-06-19T12:34:56.000\u002B00:00",
"description": "example-string",
"amount": 42,
"currency": "AED",
diff --git a/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.cs b/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.cs
index ba387683..2afddcaa 100644
--- a/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.cs
+++ b/test/WireMock.Net.Tests/OpenApiParser/WireMockOpenApiParserTests.cs
@@ -13,6 +13,7 @@ namespace WireMock.Net.Tests.OpenApiParser;
[UsesVerify]
public class WireMockOpenApiParserTests
{
+ private readonly DateTime _exampleDateTime = new(2024, 6, 19, 12, 34, 56, DateTimeKind.Utc);
private readonly Mock _exampleValuesMock = new();
private readonly WireMockOpenApiParser _sut = new();
@@ -22,12 +23,12 @@ public class WireMockOpenApiParserTests
_exampleValuesMock.SetupGet(e => e.Boolean).Returns(true);
_exampleValuesMock.SetupGet(e => e.Integer).Returns(42);
_exampleValuesMock.SetupGet(e => e.Float).Returns(1.1f);
- _exampleValuesMock.SetupGet(e => e.Double).Returns(2.2d);
+ _exampleValuesMock.SetupGet(e => e.Decimal).Returns(2.2m);
_exampleValuesMock.SetupGet(e => e.String).Returns("example-string");
_exampleValuesMock.SetupGet(e => e.Object).Returns("example-object");
_exampleValuesMock.SetupGet(e => e.Bytes).Returns("Stef"u8.ToArray());
- _exampleValuesMock.SetupGet(e => e.Date).Returns(() => new DateTime(2024, 6, 19));
- _exampleValuesMock.SetupGet(e => e.DateTime).Returns(() => new DateTime(2024, 6, 19, 12, 34, 56, DateTimeKind.Utc));
+ _exampleValuesMock.SetupGet(e => e.Date).Returns(() => _exampleDateTime.Date);
+ _exampleValuesMock.SetupGet(e => e.DateTime).Returns(() => _exampleDateTime);
}
[Fact]
diff --git a/test/WireMock.Net.Tests/OpenApiParser/payroc-openapi-spec.yaml b/test/WireMock.Net.Tests/OpenApiParser/payroc-openapi-spec.yaml
index 2c93ed18..0b56e2f3 100644
--- a/test/WireMock.Net.Tests/OpenApiParser/payroc-openapi-spec.yaml
+++ b/test/WireMock.Net.Tests/OpenApiParser/payroc-openapi-spec.yaml
@@ -8,7 +8,7 @@ info:
url: https://docs.payroc.com/api
email: helpdesk@payroc.com
servers:
- - url: https://api.payroc.com/v1
+ - url: https://api.payroc.com/v1/
description: External URL
security:
- bearerAuth: []
@@ -3734,7 +3734,7 @@ paths:
path: /a/b/c
- op: replace
path: /a/b/c
- value: 42
+ value: 420
- op: move
from: /a/b/c
path: /a/b/d
diff --git a/test/WireMock.Net.Tests/Util/PathUtilsTests.cs b/test/WireMock.Net.Tests/Util/FilePathUtilsTests.cs
similarity index 79%
rename from test/WireMock.Net.Tests/Util/PathUtilsTests.cs
rename to test/WireMock.Net.Tests/Util/FilePathUtilsTests.cs
index 52550ca0..a53aa5bf 100644
--- a/test/WireMock.Net.Tests/Util/PathUtilsTests.cs
+++ b/test/WireMock.Net.Tests/Util/FilePathUtilsTests.cs
@@ -7,7 +7,7 @@ using Xunit;
namespace WireMock.Net.Tests.Util;
-public class PathUtilsTests
+public class FilePathUtilsTests
{
[Theory]
[InlineData(@"subdirectory/MyXmlResponse.xml")]
@@ -15,7 +15,7 @@ public class PathUtilsTests
public void PathUtils_CleanPath(string path)
{
// Act
- var cleanPath = PathUtils.CleanPath(path);
+ var cleanPath = FilePathUtils.CleanPath(path);
// Assert
Check.That(cleanPath).Equals("subdirectory" + Path.DirectorySeparatorChar + "MyXmlResponse.xml");
@@ -34,10 +34,10 @@ public class PathUtilsTests
public void PathUtils_CleanPath_RemoveLeadingDirectorySeparators(string path, string expected)
{
// Arrange
- var cleanPath = PathUtils.CleanPath(path);
+ var cleanPath = FilePathUtils.CleanPath(path);
// Act
- var withoutDirectorySeparators = PathUtils.RemoveLeadingDirectorySeparators(cleanPath);
+ var withoutDirectorySeparators = FilePathUtils.RemoveLeadingDirectorySeparators(cleanPath);
// Assert
Check.That(withoutDirectorySeparators).Equals(expected);
diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
index 884ad54f..a0929ccb 100644
--- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
+++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
@@ -134,6 +134,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -150,6 +153,12 @@
Client
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
diff --git a/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs b/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs
index 57d45e44..217588c1 100644
--- a/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs
+++ b/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs
@@ -3,6 +3,7 @@
#if !NET452
using System;
using System.Collections.Generic;
+using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -319,5 +320,62 @@ public partial class WireMockServerTests
server.Stop();
}
+
+ [Fact]
+ public async Task WireMockServer_WithSseBody()
+ {
+ // Arrange
+ var server = WireMockServer.Start();
+ server
+ .WhenRequest(r => r
+ .UsingGet()
+ .WithPath("/sse")
+ )
+ .ThenRespondWith(r => r
+ .WithHeader("Content-Type", "text/event-stream")
+ .WithHeader("Cache-Control", "no-cache")
+ .WithHeader("Connection", "keep-alive")
+ .WithSseBody(async (_, queue) =>
+ {
+ for (var i = 1; i <= 3; i++)
+ {
+ queue.Write($"x {i};\r\n");
+ await Task.Delay(100);
+ }
+
+ queue.Close();
+ })
+ );
+
+ server
+ .WhenRequest(r => r
+ .UsingGet()
+ )
+ .ThenRespondWith(r => r
+ .WithBody("normal")
+ );
+
+ using var client = new HttpClient();
+
+ // Act 1
+ var normal = await new HttpClient()
+ .GetAsync(server.Url)
+ .ConfigureAwait(false);
+ (await normal.Content.ReadAsStringAsync()).Should().Be("normal");
+
+ // Act 2
+ using var response = await client.GetStreamAsync($"{server.Url}/sse");
+ using var reader = new StreamReader(response);
+
+ var data = string.Empty;
+ while (!reader.EndOfStream)
+ {
+ var line = await reader.ReadLineAsync();
+ data += line;
+ }
+
+ // Assert 2
+ data.Should().Be("x 1;x 2;x 3;");
+ }
}
#endif
\ No newline at end of file