Compare commits

..

49 Commits

Author SHA1 Message Date
Stef Heyenrath
deda7fb686 1.6.10 2024-12-15 11:39:03 +01:00
Stef Heyenrath
2a19b4491f WireMock.Net.Testcontainers: implement watching the static mapping folder for changes (#1189)
* WireMock.Net.Testcontainers: implement watching the static mapping files + folder for changes

* ReloadStaticMappings

* fix

* .

* .

* .

* .

* .

* .

* .

* CopyAsync

* <VersionPrefix>1.6.7-preview-02</VersionPrefix>

* <VersionPrefix>1.6.7-preview-03</VersionPrefix>
2024-12-15 11:31:25 +01:00
Stef Heyenrath
c548600dea 1.6.9 2024-12-06 19:22:25 +01:00
Stef Heyenrath
7f640dfa0d Fix JsonPartialMatcher when using property names with dot (#1216)
Fix JsonPartialMatcher when using property names with dot (#1216)
2024-12-06 09:23:31 +01:00
Stef Heyenrath
4b3e9feca0 1.6.8 2024-11-24 16:22:32 +01:00
Stef Heyenrath
4aaed2a6ca Fix HandlebarsContext ParseAndEvaluate method (#1213)
* Fix HandlebarsContext ParseAndEvaluate method

* test

* xxx
2024-11-22 07:58:23 +01:00
Stef Heyenrath
6f73dfe360 Use GraphQL 8.2.1 (#1211) 2024-11-18 10:23:00 +01:00
Stef Heyenrath
f4103b47aa Fix security issues (#1206)
* .

* .

* x
2024-11-17 17:25:21 +01:00
Stef Heyenrath
edab3ad7e5 WireMockLogger 2024-11-01 10:31:23 +01:00
Stef Heyenrath
38c2131472 IWireMockLogger.Error(string, Exception) 2024-10-29 19:55:02 +01:00
Stef Heyenrath
3693d6a676 Log exception when (static) mapping file cannot be read (#1202) 2024-10-29 19:52:31 +01:00
Stef Heyenrath
214fb539ec 1.6.7 2024-10-17 18:49:24 +02:00
Stef Heyenrath
a468b89788 Fix Google.Protobuf.WellKnownTypes.Value (#1198)
* <PackageReference Include="ProtoBufJsonConverter" Version="0.5.0-preview-01" />

* Fix Google.Protobuf.WellKnownTypes.Value
2024-10-17 18:47:09 +02:00
Stef Heyenrath
1682c61a0c Use latest ProtoBufJsonConverter to support WellKnownTypes (#1161)
* Use latest ProtoBufJsonConverter to support WellKnownTypes

* Fix

* 02

* WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes

* .

* extra test

* 0.4.0-preview-06

* 7

* <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0-preview-08" />

* Update README.md

* <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0-preview-09" />

* <PackageReference Include="ProtoBufJsonConverter" Version="0.4.0" />

* Update README.md
2024-10-16 10:57:47 +02:00
dependabot[bot]
ac693e0f96 Bump System.Text.Json from 8.0.4 to 8.0.5 in /src/dotnet-WireMock.Net (#1197)
Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.4 to 8.0.5.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v8.0.4...v8.0.5)

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-16 10:41:07 +02:00
dependabot[bot]
45755adae4 Bump System.Text.Json in /examples/WireMock.Net.Console.Net472.Classic (#1190)
Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.4 to 8.0.5.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v8.0.4...v8.0.5)

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-15 21:46:08 +02:00
Stef Heyenrath
2ffdae1863 Upgrade System.Text.RegularExpressions to 4.3.1 to solve CVE-2019-0820 (#1194)
* Upgrade Handlebars.Net.Helpers to 2.4.6 to solve CVE-2019-0820

* .
2024-10-10 08:29:57 +02:00
Stef Heyenrath
5adbff0fa3 Update README.md (add blog) 2024-10-06 18:31:46 +02:00
Stef Heyenrath
5e04ff1a42 Add an architecture diagram for Aspire project (#1174)
* Add an architecture diagram for Aspire project

* .

* "WireMock.Net : " +

* .
2024-10-04 19:30:47 +02:00
Stef Heyenrath
eb7e6c397f 1.6.6 2024-10-01 17:43:18 +02:00
Stef Heyenrath
f56ecf943d Fix StaticMappingsPath in WireMockContainerBuilder (#1187)
* Fix StaticMappingsPath in WireMockContainerBuilder

* .
2024-10-01 17:39:59 +02:00
Stef Heyenrath
76ae1466cc Throw exception in case WithTransformer is used after WithBodyFromFile (#1185)
* Fix .WithBodyFromFile + .WithTransformer combination

* Ex
2024-09-29 21:29:34 +02:00
Stef Heyenrath
edbc7aeb5c 1.6.5 2024-09-28 10:26:38 +02:00
Stef Heyenrath
42306d1864 Add WireMock.Net.AspNetCore.Middleware (#1175)
* Add WireMock.Net.AspNetCore.Middleware

* .

* WireMock.Net.Middleware.Tests

* .

* X-WireMock-Response-Delay
2024-09-27 20:39:57 +02:00
Stef Heyenrath
c57590b2ba Set <SonarQubeExclude>true</SonarQubeExclude> in test projects (#1183) 2024-09-27 20:06:22 +02:00
Stef Heyenrath
dca3fd0260 WireMock.Net.Testcontainers: Use 'sheyenrath/wiremock.net-alpine' image as default for Linux (#1181)
* WireMock.Net.Testcontainers: Use 'sheyenrath/wiremock.net-alpine' image as default for Linux

* ...

* .

* WithBindMount

* fix

* r

* .
2024-09-27 19:10:51 +02:00
Jason Landbridge
95994421ae pass in the request when no matching is found to the warn logger (#1182) 2024-09-27 19:10:39 +02:00
Stef Heyenrath
697411555a Update README.md (add WireMock.Net.TUnit) 2024-09-26 18:47:36 +02:00
Stef Heyenrath
f89f0fa466 1.6.4 2024-09-25 08:56:44 +02:00
Stef Heyenrath
b892e85d2a Add WireMock.Net.TUnit project (#1179)
* Add WireMock.Net.TUnit project

* fix

* .

* fix

* bd

* 0.1.812

* dotnet test

* 0.1.817

* cat

* type

* type2

* find

* -- --diagnostic

* --no-build

* fix?
2024-09-25 08:52:40 +02:00
Stef Heyenrath
836976ca19 Upgrade CS-Script to version 4.8.17 (#1178) 2024-09-20 15:20:38 +02:00
Stef Heyenrath
c845f73dd0 Unpin Testcontainers version and upgrade to version 3.10.0 (#1177) 2024-09-20 15:20:25 +02:00
Stef Heyenrath
2cbbef01ae Refactor some code (IBodyDataExtensions) 2024-09-20 13:52:45 +02:00
Ruxo
dd80fd7822 Attempt to fix JSON parsing of text/plain content type (#1172)
* UseContentType

* Fix unit tests

* Add a unit test and an integration test for the fix.

* Simplify body type checking with GetBodyType extension.

* Split IBodyDataExtension, and use imperative style instead of functional style

* Remove excessive null forgiving operators

* Adjust braces

---------

Co-authored-by: Ruxo Zheng <rz@just.sent.as>
2024-09-20 13:19:32 +02:00
Stef Heyenrath
527278e60c Update the .NET Aspire tests (#1170)
* Skip unit tests when Docker is not running in Linux container mode using DockerIsRunningInLinuxContainerModeFact

* IgnoreOnContinuousIntegrationFact
2024-09-10 16:14:05 +02:00
Stef Heyenrath
7d7f1f8fbb Allow mapping without Path or Url (#1169) 2024-09-09 20:48:09 +02:00
Stef Heyenrath
af124d556d 1.6.3 2024-09-07 09:36:33 +02:00
cocoon
60931f6273 Fix listen on AnyIP for url 0.0.0.0 (#1165)
* fix listen to AnyIP if url is 0.0.0.0

* Add Test for listenin on AnyIP for url 0.0.0.0

* add missing using, use var, indent, remove empty line

* remove assert for ipv4/v6 address list

* test only if NET6_0_OR_GREATER

* use same code style

* add missing +

* Asser. to Assert

* split single test into one for IPv4 and one for IPv6

* Create IgnoreOnContinuousIntegrationFact.cs

* Ignore tests if CI/CD

* change to file - scoped namespace and add GITHUB_ACTIONS

* use PortUtils.FindFreeTcpPort()

* add and use GetIPAddressesByFamily

* add using System.Net.Sockets

* use #if for both unit tests and include new helper method inside
2024-09-07 09:31:19 +02:00
Stef Heyenrath
b99a80e782 Update README.md (Fix NuGet and MyGet badges) 2024-09-06 15:11:30 +02:00
Stef Heyenrath
07c9aebf44 1.6.2 2024-09-04 18:50:59 +02:00
Stef Heyenrath
8348a7b9a3 Also update IWireMockMiddlewareOptions when settings are updated via admin interface (#1166)
* Also update IWireMockMiddlewareOptions when settings are updated via admin interface

* ci
2024-09-04 18:47:25 +02:00
Stef Heyenrath
9a49e6a1cd Upgrade Aspire to version 8.2.0 (#1163) 2024-08-31 17:06:30 +02:00
Stef Heyenrath
f82891c996 Fix version from "WireMock.Net.Aspire" 2024-08-29 18:51:25 +02:00
Stef Heyenrath
da100298c1 Update MappingConverter to correctly write the Matcher as C# code (#1152)
* Update MappingConverter to correctly write the Matcher as C# code

* .

* CSharpCodeMatcher

* tests

* .
2024-08-27 19:38:07 +02:00
Stef Heyenrath
95573eeb96 1.6.1 2024-08-22 20:33:39 +02:00
Stef Heyenrath
487d6d2db1 Use default timeout for Regex (#1160) 2024-08-22 20:31:03 +02:00
Stef Heyenrath
d2b53893db 1.6.0 2024-08-16 13:19:07 +02:00
Stef Heyenrath
088444024f Allow setting Content-Length header on the response (#1158)
* Allow setting Content-Length header on the response

* fix?
2024-08-16 12:14:42 +02:00
Stef Heyenrath
7e162a00ab Fix FormUrlEncodedMatcher (MatchOperator.And) (#1157) 2024-08-15 11:01:37 +02:00
186 changed files with 4394 additions and 1027 deletions

View File

@@ -19,8 +19,14 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: 'Execute Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Middleware.Tests'
run: dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0
linux-build-and-run:
name: Run Tests on Linux
@@ -32,11 +38,17 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: 'Execute Tests'
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Middleware.Tests'
run: dotnet test './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj' -c Release --framework net8.0
- name: Install .NET Aspire workload
run: dotnet workload install aspire
- name: 'Execute .NET Aspire Tests'
- name: 'WireMock.Net.Aspire.Tests'
run: dotnet test './test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj' -c Release

View File

@@ -1,3 +1,78 @@
# 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 &quot;D&quot; 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]
@@ -17,9 +92,7 @@
# 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)
- [#1131](https://github.com/WireMock-Net/WireMock.Net/pull/1131) - Add unit tests for AdminApiMappingBuilder [test] 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)
- [#1133](https://github.com/WireMock-Net/WireMock.Net/pull/1133) - Add unit tests for AdminApiMappingBuilder_ [test] contributed by [StefH](https://github.com/StefH)
- [#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]
@@ -104,7 +177,6 @@
# 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)
- [#1029](https://github.com/WireMock-Net/WireMock.Net/pull/1029) - Add ResponseWithHandlebarsDateTimeTests [test] 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=&quot;Long&quot; [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]
@@ -113,12 +185,9 @@
# 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)
- [#1020](https://github.com/WireMock-Net/WireMock.Net/pull/1020) - Add Github Action [test] 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)
- [#1009](https://github.com/WireMock-Net/WireMock.Net/pull/1009) - Add more tests for JmesPathMatchers and StringUtils.ParseMatchOperator [test] contributed by [StefH](https://github.com/StefH)
- [#1010](https://github.com/WireMock-Net/WireMock.Net/pull/1010) - Add unit tests for HttpClient with WebProxy [test] contributed by [StefH](https://github.com/StefH)
- [#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)
@@ -130,7 +199,6 @@
- [#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)
- [#998](https://github.com/WireMock-Net/WireMock.Net/pull/998) - Add JmesPathMatcher UnitTests [test] contributed by [StefH](https://github.com/StefH)
- [#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 &quot;IgnoreCase&quot; property of HeaderModel [bug]
@@ -142,7 +210,6 @@
- [#1001](https://github.com/WireMock-Net/WireMock.Net/issues/1001) - SaveUnmatchedRequests stopped working [bug]
# 1.5.35 (19 August 2023)
- [#992](https://github.com/WireMock-Net/WireMock.Net/pull/992) - Add extra unit test for WithParam multiple values comma [test] contributed by [StefH](https://github.com/StefH)
- [#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)
@@ -168,7 +235,6 @@
# 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)
- [#961](https://github.com/WireMock-Net/WireMock.Net/pull/961) - Add unit-test for Param MatcherModel LinqMatcher [test] 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]
@@ -189,7 +255,6 @@
- [#945](https://github.com/WireMock-Net/WireMock.Net/issues/945) - Webhook logging [feature]
# 1.5.26 (25 May 2023)
- [#938](https://github.com/WireMock-Net/WireMock.Net/pull/938) - Add more unitests for CSharpFormatter utils [test] contributed by [StefH](https://github.com/StefH)
- [#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)
@@ -238,7 +303,6 @@
# 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)
- [#882](https://github.com/WireMock-Net/WireMock.Net/pull/882) - Add example code to test HTTP Status 400 and 500 [test] 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)
@@ -254,7 +318,6 @@
- [#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)
- [#877](https://github.com/WireMock-Net/WireMock.Net/pull/877) - Add unit test example for Transformer Handlebars String.Append String.Join [test] contributed by [StefH](https://github.com/StefH)
- [#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]
@@ -334,7 +397,6 @@
# 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)
- [#770](https://github.com/WireMock-Net/WireMock.Net/pull/770) - Added some more tests for JsonMatcher + refactored some code to use nullable [test] contributed by [StefH](https://github.com/StefH)
- [#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)
@@ -620,9 +682,6 @@
- [#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 &quot;blacklist&quot; and &quot;whitelist&quot; terms [feature]
# 1.2.15 (19 July 2020)
- [#485](https://github.com/WireMock-Net/WireMock.Net/pull/485) - Add fluent assertions for headers [test] contributed by [akamud](https://github.com/akamud)
# 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)
@@ -923,7 +982,6 @@
# 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)
- [#229](https://github.com/WireMock-Net/WireMock.Net/pull/229) - Fix proxy tests [test] 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)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.5.62</VersionPrefix>
<VersionPrefix>1.6.10</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
@@ -43,13 +43,22 @@
</When>
</Choose>
<PropertyGroup>
<NuGetAudit>true</NuGetAudit>
<!--<NuGetAuditLevel>low</NuGetAuditLevel>-->
<NuGetAuditMode>all</NuGetAuditMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<!-- CVE-2019-0820 -->
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.29.0.95321">
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,7 +1,7 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.5.62
SET version=1.6.10
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
GitHubReleaseNotes --output PackageReleaseNotes.txt --skip-empty-releases --exclude-labels question invalid doc duplicate example environment --template PackageReleaseNotes.template --version %version% --token %GH_TOKEN%
GitHubReleaseNotes --output PackageReleaseNotes.txt --skip-empty-releases --exclude-labels test question invalid doc duplicate example environment --template PackageReleaseNotes.template --version %version% --token %GH_TOKEN%

View File

@@ -1,5 +1,5 @@
# 1.5.62 (27 July 2024)
- #1147 Add FormUrlEncodedMatcher [feature]
- #1143 FormEncoded Request fails (404 Not Found) if key value pairs order in mapping is different from request body order [bug]
# 1.6.10 (15 December 2024)
- #1189 WireMock.Net.Testcontainers: implement watching the static mapping folder for changes [bug]
- #1188 WithWatchStaticMappings doesn't respect new files [bug]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -16,9 +16,10 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
* Can be used for Aspire Distributed Application testing
## :memo: Blogs
- [mstack.nl : Generate C# Code from Mapping(s)](https://mstack.nl/blog/20230201-wiremock.net-tocode/)
- [mstack.nl : Chaos Engineering with Fault Injections](https://mstack.nl/blogs/wiremock-net-chaos-engineering-with-fault-injections/)
- [mstack.nl : gRPC / ProtoBuf Support](https://mstack.nl/blogs/wiremock-net-grpc/)
- [mstack.nl : Generate C# Code from Mapping(s)](https://mstack.nl/blog/20230201-wiremock.net-tocode)
- [mstack.nl : Chaos Engineering with Fault Injections](https://mstack.nl/blogs/wiremock-net-chaos-engineering-with-fault-injections)
- [mstack.nl : gRPC / ProtoBuf Support](https://mstack.nl/blogs/wiremock-net-grpc)
- [mstack.nl : Build and test your own .NET Aspire component](https://mstack.nl/blogs/wiremock-net-aspire-component/)
## :computer: Project Info
@@ -39,16 +40,21 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
| | Official | Preview [:information_source:](https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions) |
| - | - | - |
| &nbsp;&nbsp;**WireMock.Net** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) | [![MyGet Badge WireMock.Net](https://buildstats.info/myget/wiremock-net/WireMock.Net?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net)
| &nbsp;&nbsp;**WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://buildstats.info/nuget/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://buildstats.info/myget/wiremock-net/WireMock.Net.StandAlone?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
| &nbsp;&nbsp;**WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/nuget/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://buildstats.info/myget/wiremock-net/WireMock.Net.FluentAssertions?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions)
| &nbsp;&nbsp;**WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/nuget/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://buildstats.info/myget/wiremock-net/WireMock.Net.Matchers.CSharpCode?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
| &nbsp;&nbsp;**WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/nuget/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/myget/wiremock-net/WireMock.Net.OpenApiParser?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
| &nbsp;&nbsp;**WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://buildstats.info/nuget/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Net.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
| &nbsp;&nbsp;**WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://buildstats.info/nuget/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://buildstats.info/myget/wiremock-net/WireMock.Net.xUnit?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
| &nbsp;&nbsp;**WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://buildstats.info/nuget/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://buildstats.info/myget/wiremock-net/WireMock.Net.Testcontainers?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
| &nbsp;&nbsp;**WireMock.Net.Aspire** | [![NuGet Badge WireMock.Net.Aspire](https://buildstats.info/nuget/WireMock.Net.Aspire)](https://www.nuget.org/packages/WireMock.Net.Aspire) | [![MyGet Badge WireMock.Net.Aspire](https://buildstats.info/myget/wiremock-net/WireMock.Net.Aspire?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire)
| &nbsp;&nbsp;**WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://buildstats.info/nuget/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Org.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
| &nbsp;&nbsp;**WireMock.Net** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) | [![MyGet Badge WireMock.Net](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net)
| &nbsp;&nbsp;**WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.StandAlone?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
| &nbsp;&nbsp;**WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://img.shields.io/nuget/v/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Testcontainers?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
| &nbsp;&nbsp;**WireMock.Net.Aspire** | [![NuGet Badge WireMock.Net.Aspire](https://img.shields.io/nuget/v/WireMock.Net.Aspire)](https://www.nuget.org/packages/WireMock.Net.Aspire) | [![MyGet Badge WireMock.Net.Aspire](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Aspire?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire)
| &nbsp;&nbsp;**WireMock.Net.AspNetCore.Middleware** | [![NuGet Badge WireMock.Net.AspNetCore.Middleware](https://img.shields.io/nuget/v/WireMock.Net.AspNetCore.Middleware)](https://www.nuget.org/packages/WireMock.Net.AspNetCore.Middleware) | [![MyGet Badge WireMock.Net.AspNetCore.Middleware](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.AspNetCore.Middleware?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.AspNetCore.Middleware)
| | | |
| &nbsp;&nbsp;**WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/nuget/v/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.FluentAssertions?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions)
| &nbsp;&nbsp;**WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://img.shields.io/nuget/v/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.xUnit?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
| &nbsp;&nbsp;**WireMock.Net.TUnit** | [![NuGet Badge WireMock.Net.TUnit](https://img.shields.io/nuget/v/WireMock.Net.TUnit)](https://www.nuget.org/packages/WireMock.Net.TUnit) | [![MyGet Badge WireMock.Net.TUnit](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.TUnit?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.TUnit)
| | | |
| &nbsp;&nbsp;**WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/nuget/v/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Matchers.CSharpCode?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
| &nbsp;&nbsp;**WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/nuget/v/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.OpenApiParser?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
| | | |
| &nbsp;&nbsp;**WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://img.shields.io/nuget/v/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
| &nbsp;&nbsp;**WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://img.shields.io/nuget/v/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Org.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
## :memo: Development

View File

@@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8F890C6F-9ACC-438D-928A-AD61CDA862F2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0BB8B634-407A-4610-A91F-11586990767A}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net", "src\WireMock.Net\WireMock.Net.csproj", "{D3804228-91F4-4502-9595-39584E5A01AD}"
EndProject
@@ -131,6 +134,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Aspire.TestApp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspireApp1.AppHostOriginal", "examples-Aspire\AspireApp1.AppHostOriginal\AspireApp1.AppHostOriginal.csproj", "{C9210DA3-F390-4598-8512-349A473FE9C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnit", "src\WireMock.Net.TUnit\WireMock.Net.TUnit.csproj", "{91024A93-848F-4A02-AF53-5EBE5834E23C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TUnitTests", "test\WireMock.Net.TUnitTests\WireMock.Net.TUnitTests.csproj", "{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication", "examples\WireMock.Net.WebApplication\WireMock.Net.WebApplication.csproj", "{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.AspNetCore.Middleware", "src\WireMock.Net.AspNetCore.Middleware\WireMock.Net.AspNetCore.Middleware.csproj", "{B6269AAC-170A-4346-8B9A-579DED3D9A13}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TestWebApplication", "test\WireMock.Net.TestWebApplication\WireMock.Net.TestWebApplication.csproj", "{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Middleware.Tests", "test\WireMock.Net.Middleware.Tests\WireMock.Net.Middleware.Tests.csproj", "{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -317,6 +332,30 @@ Global
{C9210DA3-F390-4598-8512-349A473FE9C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9210DA3-F390-4598-8512-349A473FE9C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9210DA3-F390-4598-8512-349A473FE9C9}.Release|Any CPU.Build.0 = Release|Any CPU
{91024A93-848F-4A02-AF53-5EBE5834E23C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91024A93-848F-4A02-AF53-5EBE5834E23C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91024A93-848F-4A02-AF53-5EBE5834E23C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91024A93-848F-4A02-AF53-5EBE5834E23C}.Release|Any CPU.Build.0 = Release|Any CPU
{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CD237F7-B616-46B8-872F-E49B4BBB3EAE}.Release|Any CPU.Build.0 = Release|Any CPU
{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E72ADFAB-4B42-439E-B1EE-C06E504B35D2}.Release|Any CPU.Build.0 = Release|Any CPU
{B6269AAC-170A-4346-8B9A-579DED3D9A13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6269AAC-170A-4346-8B9A-579DED3D9A13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6269AAC-170A-4346-8B9A-579DED3D9A13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6269AAC-170A-4346-8B9A-579DED3D9A13}.Release|Any CPU.Build.0 = Release|Any CPU
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE}.Release|Any CPU.Build.0 = Release|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -369,6 +408,12 @@ Global
{CE602F57-FEF8-4559-A9E0-6200BE1BF398} = {0BB8B634-407A-4610-A91F-11586990767A}
{F1B5999D-D22E-48A6-AB86-18A7876BD32E} = {0BB8B634-407A-4610-A91F-11586990767A}
{C9210DA3-F390-4598-8512-349A473FE9C9} = {AD474543-0715-49F2-A284-936B060BF736}
{91024A93-848F-4A02-AF53-5EBE5834E23C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{4CD237F7-B616-46B8-872F-E49B4BBB3EAE} = {0BB8B634-407A-4610-A91F-11586990767A}
{E72ADFAB-4B42-439E-B1EE-C06E504B35D2} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{B6269AAC-170A-4346-8B9A-579DED3D9A13} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE} = {0BB8B634-407A-4610-A91F-11586990767A}
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

@@ -33,6 +33,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Guids/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heyenrath/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Jmes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Levenstein/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=openapi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pacticipant/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=protobuf/@EntryIndexedValue">True</s:Boolean>

View File

@@ -38,7 +38,7 @@ jobs:
# See: https://docs.sonarsource.com/sonarcloud/enriching/test-coverage/dotnet-test-coverage
- script: |
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.dotnet.excludeTestProjects=true /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
displayName: 'Begin analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
@@ -52,9 +52,26 @@ jobs:
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-1.xml"
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-2.xml"
displayName: 'Execute Unit Tests with Coverage'
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'WireMock.Net.Aspire.Tests with Coverage'
- task: CmdLine@2
displayName: 'Merge coverage files'
@@ -98,18 +115,25 @@ jobs:
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0'
- task: DotNetCoreCLI@2
displayName: 'Execute Unit Tests with Coverage'
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--no-build --configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test

View File

@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.0" />
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>

View File

@@ -2,20 +2,49 @@ using AspireApp1.AppHost;
var builder = DistributedApplication.CreateBuilder(args);
//IResourceBuilder<ProjectResource> apiService = builder.AddProject<Projects.AspireApp1_ApiService>("apiservice");
// IResourceBuilder<ProjectResource> apiService = builder.AddProject<Projects.AspireApp1_ApiService>("apiservice");
var mappingsPath = Path.Combine(Directory.GetCurrentDirectory(), "WireMockMappings");
Console.WriteLine($"MappingsPath: {mappingsPath}");
var wiremock = builder
IResourceBuilder<WireMockServerResource> apiService = builder
.AddWireMock("apiservice", WireMockServerArguments.DefaultPort)
.WithMappingsPath(mappingsPath)
.WithReadStaticMappings()
.WithWatchStaticMappings()
.WithApiMappingBuilder(WeatherForecastApiMock.BuildAsync);
//var apiServiceUsedForDocs = builder
// .AddWireMock("apiservice1", WireMockServerArguments.DefaultPort)
// .WithApiMappingBuilder(adminApiBuilder =>
// {
// var summaries = new[]
// {
// "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
// };
// adminApiBuilder.Given(b => b
// .WithRequest(request => request
// .UsingGet()
// .WithPath("/weatherforecast2")
// )
// .WithResponse(response => response
// .WithHeaders(h => h.Add("Content-Type", "application/json"))
// .WithBodyAsJson(() => Enumerable.Range(1, 5).Select(index =>
// new WeatherForecast
// (
// DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
// Random.Shared.Next(-20, 55),
// "WireMock.Net : " + summaries[Random.Shared.Next(summaries.Length)]
// ))
// .ToArray())
// )
// );
// return Task.CompletedTask;
// });
builder.AddProject<Projects.AspireApp1_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(wiremock);
.WithReference(apiService);
builder.Build().Run();

View File

@@ -4,7 +4,7 @@ namespace AspireApp1.AppHost;
internal class WeatherForecastApiMock
{
public static async Task BuildAsync(AdminApiMappingBuilder builder)
public static async Task BuildAsync(AdminApiMappingBuilder builder, CancellationToken cancellationToken)
{
var summaries = new[]
{
@@ -23,13 +23,13 @@ internal class WeatherForecastApiMock
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
"WireMock.Net 2 : " + summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray())
)
);
await builder.BuildAndPostAsync();
await builder.BuildAndPostAsync(cancellationToken);
}
}

View File

@@ -11,27 +11,27 @@
{
"date": "2024-05-24",
"temperatureC": -17,
"summary": "Balmy"
"summary": "WireMock.Net 1 : Balmy"
},
{
"date": "2024-05-25",
"temperatureC": -13,
"summary": "Mild"
"summary": "WireMock.Net 1 : Mild"
},
{
"date": "2024-05-26",
"temperatureC": 31,
"summary": "Bracing"
"summary": "WireMock.Net 1 : Bracing"
},
{
"date": "2024-05-27",
"temperatureC": 6,
"summary": "Hot"
"summary": "WireMock.Net 1 : Hot"
},
{
"date": "2024-05-28",
"temperatureC": -2,
"summary": "Mild"
"summary": "WireMock.Net 1 : Mild"
}
],
"Headers": {

View File

@@ -14,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.0" />
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>

View File

@@ -137,7 +137,6 @@ message HelloReply {
public static void Run()
{
RunOnLocal();
return;
var mappingBuilder = new MappingBuilder();
mappingBuilder
@@ -308,17 +307,6 @@ message HelloReply {
.RespondWith(Response.Create()
.WithBody("GraphQL is ok")
);
//server
// .AddGraphQLSchema("my-graphql", TestSchema, customScalars)
// .Given(Request.Create()
// .WithPath("/graphql2")
// .UsingPost()
// )
// .WithGraphQLSchema("my-graphql")
// .RespondWith(Response.Create()
// .WithBody("GraphQL is ok")
// );
#endif
#if MIMEKIT
@@ -377,6 +365,15 @@ message HelloReply {
.WithHeader("Content-Type", "text/plain")
);
server
.Given(Request.Create()
.UsingHead()
.WithPath("/cl")
)
.RespondWith(Response.Create()
.WithHeader("Content-Length", "42")
);
server
.Given(Request.Create()
.UsingMethod("GET")

View File

@@ -39,7 +39,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
@@ -47,31 +47,31 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Handlebars" publicKeyToken="22225d0bf33cd661" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.2.0" newVersion="2.1.2.0" />
<bindingRedirect oldVersion="0.0.0.0-2.1.6.0" newVersion="2.1.6.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Core" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.1.2" newVersion="2.4.1.2" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="XPath2" publicKeyToken="463c6d7fb740c7e5" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.4.0" newVersion="1.1.4.0" />
<bindingRedirect oldVersion="0.0.0.0-1.1.5.0" newVersion="1.1.5.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.5.1" newVersion="4.0.5.1" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Handlebars.Net.Helpers" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.1.2" newVersion="2.4.1.2" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq.Dynamic.Core" publicKeyToken="0f07ec44de6ac832" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.23.0" newVersion="1.2.23.0" />
<bindingRedirect oldVersion="0.0.0.0-1.3.14.0" newVersion="1.3.14.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Fare" publicKeyToken="ea68d375bf33a7c8" culture="neutral" />
@@ -83,7 +83,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Json" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.3.10.0" newVersion="2.3.10.0" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
@@ -91,20 +91,324 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.25.0.0" newVersion="6.25.0.0" />
<bindingRedirect oldVersion="0.0.0.0-7.2.0.0" newVersion="7.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.25.0.0" newVersion="6.25.0.0" />
<bindingRedirect oldVersion="0.0.0.0-7.2.0.0" newVersion="7.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.25.0.0" newVersion="6.25.0.0" />
<bindingRedirect oldVersion="0.0.0.0-6.34.0.0" newVersion="6.34.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NJsonSchema" publicKeyToken="c2f9c3bdfae56102" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.7.2.0" newVersion="10.7.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="AnyOf" publicKeyToken="b35e6abbb527c6b1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.3.0.0" newVersion="0.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.DynamicLinq" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Humanizer" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Random" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Xeger" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.XPath" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Humanizer" publicKeyToken="979442b78dfc278e" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.14.0.0" newVersion="2.14.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="JmesPath.Net" publicKeyToken="b29d616b7f4faff0" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.125.0" newVersion="1.0.125.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.17.0" newVersion="2.0.17.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Authentication.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Authentication.Core" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Connections.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Diagnostics" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Diagnostics.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.HostFiltering" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Hosting" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Hosting.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Hosting.Server.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Http" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Http.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Http.Extensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Http.Features" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.HttpOverrides" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Routing" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Routing.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.IISIntegration" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.Kestrel" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.Kestrel.Core" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.Kestrel.Https" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.WebUtilities" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.Binder" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.CommandLine" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.EnvironmentVariables" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.FileExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.Json" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Configuration.UserSecrets" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.FileProviders.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.FileProviders.Physical" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.FileSystemGlobbing" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Hosting.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Console" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Debug" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.EventSource" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.ObjectPool" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Abstractions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.2.0.0" newVersion="7.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.2.0.0" newVersion="7.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Protocols" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.12.2.0" newVersion="6.12.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Protocols.OpenIdConnect" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.12.2.0" newVersion="6.12.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Net.Http.Headers" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Namotion.Reflection" publicKeyToken="c2f9c3bdfae56102" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.10.0" newVersion="2.0.10.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NJsonSchema.Extensions" publicKeyToken="e52fadf300daf456" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.1.0.0" newVersion="0.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NSwag.Core" publicKeyToken="c2d88086e098d109" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.16.1.0" newVersion="13.16.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="RandomDataGenerator" publicKeyToken="ae5c571d29a3b8d9" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.16.0" newVersion="1.0.16.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Scriban.Signed" publicKeyToken="5675fb69b15f2433" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.4.0" newVersion="2.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SimMetrics.Net" publicKeyToken="c58dc06d59f3391b" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.5.0" newVersion="1.0.5.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Pipelines" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.8.0" newVersion="5.2.8.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.4.3.0" newVersion="1.4.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Principal.Windows" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.5" newVersion="8.0.0.5" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="TinyMapper" publicKeyToken="null" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="XPath2.Extensions" publicKeyToken="463c6d7fb740c7e5" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.5.0" newVersion="1.1.5.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -158,7 +158,7 @@
<HintPath>..\..\packages\Microsoft.AspNetCore.WebUtilities.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\..\packages/Microsoft.Bcl.AsyncInterfaces.8.0.0/lib/net462/Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
@@ -234,15 +234,15 @@
<HintPath>..\..\packages\Microsoft.Extensions.Primitives.5.0.0\lib\net461\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Abstractions, Version=7.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages/Microsoft.IdentityModel.Abstractions.7.2.0/lib/net472/Microsoft.IdentityModel.Abstractions.dll</HintPath>
<HintPath>..\..\packages\Microsoft.IdentityModel.Abstractions.7.2.0\lib\net472\Microsoft.IdentityModel.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.IdentityModel.JsonWebTokens, Version=7.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages/Microsoft.IdentityModel.JsonWebTokens.7.2.0/lib/net472/Microsoft.IdentityModel.JsonWebTokens.dll</HintPath>
<HintPath>..\..\packages\Microsoft.IdentityModel.JsonWebTokens.7.2.0\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.IdentityModel.Logging, Version=7.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages/Microsoft.IdentityModel.Logging.7.2.0/lib/net472/Microsoft.IdentityModel.Logging.dll</HintPath>
<HintPath>..\..\packages\Microsoft.IdentityModel.Logging.7.2.0\lib\net472\Microsoft.IdentityModel.Logging.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.IdentityModel.Protocols, Version=6.12.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@@ -252,7 +252,7 @@
<HintPath>..\..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.6.12.2\lib\net472\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Tokens, Version=7.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages/Microsoft.IdentityModel.Tokens.7.2.0/lib/net472/Microsoft.IdentityModel.Tokens.dll</HintPath>
<HintPath>..\..\packages\Microsoft.IdentityModel.Tokens.7.2.0\lib\net472\Microsoft.IdentityModel.Tokens.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Net.Http.Headers, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
@@ -302,7 +302,7 @@
<HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.5.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.IdentityModel.Tokens.Jwt, Version=6.34.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages/System.IdentityModel.Tokens.Jwt.6.34.0/lib/net472/System.IdentityModel.Tokens.Jwt.dll</HintPath>
<HintPath>..\..\packages\System.IdentityModel.Tokens.Jwt.6.34.0\lib\net472\System.IdentityModel.Tokens.Jwt.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.Pipelines, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
@@ -312,7 +312,7 @@
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.3.14\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\..\packages/System.Memory.4.5.5/lib/net461/System.Memory.dll</HintPath>
<HintPath>..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net" />
@@ -328,7 +328,7 @@
<HintPath>..\..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<HintPath>..\..\packages/System.Runtime.CompilerServices.Unsafe.6.0.0/lib/net461/System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.Serialization" />
@@ -339,11 +339,11 @@
<HintPath>..\..\packages\System.Security.Principal.Windows.4.5.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\..\packages/System.Text.Encodings.Web.8.0.0/lib/net462/System.Text.Encodings.Web.dll</HintPath>
<HintPath>..\..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\..\packages/System.Text.Json.8.0.4/lib/net462/System.Text.Json.dll</HintPath>
<Reference Include="System.Text.Json, Version=8.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\..\packages\System.Text.Json.8.0.5\lib\net462\System.Text.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">

View File

@@ -147,7 +147,7 @@
<package id="System.Security.Principal.Windows" version="4.5.0" targetFramework="net472" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net472" />
<package id="System.Text.Json" version="8.0.4" targetFramework="net472" />
<package id="System.Text.Json" version="8.0.5" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
<package id="TinyMapper" version="3.0.3" targetFramework="net472" />

View File

@@ -1,7 +1,8 @@
// Copyright © WireMock.Net
using DotNet.Testcontainers.Configurations;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Testcontainers.MsSql;
using WireMock.Net.Testcontainers;
namespace WireMock.Net.TestcontainersExample;
@@ -10,18 +11,184 @@ internal class Program
{
private static async Task Main(string[] args)
{
var container = new WireMockContainerBuilder()
.WithAdminUserNameAndPassword("x", "y")
.WithMappings(@"C:\Dev\GitHub\WireMock.Net\examples\WireMock.Net.Console.NET6\__admin\mappings")
var original = Console.ForegroundColor;
try
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine("Copy");
await TestCopyAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine("Automatic");
await TestAsync();
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Linux");
await TestAsync("sheyenrath/wiremock.net:1.6.5");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Linux Alpine");
await TestAsync("sheyenrath/wiremock.net-alpine:1.6.5");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("WithLinux");
await TestAsync("WithLinux");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Windows");
await TestAsync("sheyenrath/wiremock.net-windows:1.6.5");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
try
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("WithWindows");
await TestAsync("WithWindows");
await Task.Delay(1_000);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Console.ForegroundColor = original;
}
}
private static async Task TestCopyAsync()
{
var builder = new WireMockContainerBuilder()
.WithWatchStaticMappings(true)
.WithAutoRemove(true)
.WithCleanUp(true)
.Build();
.WithCleanUp(true);
await container.StartAsync().ConfigureAwait(false);
var container = builder.Build();
var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1)).ConfigureAwait(false);
Console.WriteLine("logs = " + logs.Stdout);
await container.StartAsync();
if (await GetImageOSAsync.Value == OSPlatform.Linux)
{
try
{
await container.CopyAsync(@"C:\temp-wiremock\__admin\mappings\StefBodyAsFileExample.json", "/app/__admin/mappings");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
Console.WriteLine("PublicUrl = " + container.GetPublicUrl());
var adminClient = container.CreateWireMockAdminClient();
var mappings = await adminClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
await Task.Delay(1_000);
//Console.WriteLine("Press any key to stop.");
//Console.ReadKey();
await container.StopAsync();
}
private static async Task TestAsync(string? image = null)
{
var mappingsPath = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..", "WireMock.Net.Console.NET6", "__admin", "mappings");
var builder = new WireMockContainerBuilder()
.WithAdminUserNameAndPassword("x", "y")
.WithMappings(mappingsPath)
.WithWatchStaticMappings(true)
.WithAutoRemove(true)
.WithCleanUp(true);
if (image != null)
{
builder = image switch
{
"WithWindows" => builder.WithWindowsImage(),
"WithLinux" => builder.WithLinuxImage(),
_ => builder.WithImage(image)
};
}
var container = builder.Build();
await container.StartAsync();
await container.ReloadStaticMappingsAsync();
//var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1));
//Console.WriteLine("logs = " + logs.Stdout);
Console.WriteLine("PublicUrl = " + container.GetPublicUrl());
var restEaseApiClient = container.CreateWireMockAdminClient();
@@ -29,17 +196,32 @@ internal class Program
Console.WriteLine("settings = " + JsonConvert.SerializeObject(settings, Formatting.Indented));
var mappings = await restEaseApiClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
Console.WriteLine("mappingsStef = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
var client = container.CreateClient();
var result = await client.GetStringAsync("/static/mapping");
Console.WriteLine("result = " + result);
await container.StopAsync();
//if (image == null)
//{
// Console.WriteLine("Press any key to stop.");
// Console.ReadKey();
//}
var sql = new MsSqlBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.Build();
await container.StopAsync();
}
private static Lazy<Task<OSPlatform>> GetImageOSAsync = new(async () =>
{
if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null)
{
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
}
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
using var dockerClient = dockerClientConfig.CreateClient();
var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
});
}

View File

@@ -1,24 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Testcontainers.MsSql" Version="3.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,56 @@
using WireMock.Net.AspNetCore.Middleware;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsProduction())
{
builder.Services.AddWireMockService(server =>
{
server.Given(Request.Create()
.WithPath("/test1")
.UsingAnyMethod()
).RespondWith(Response.Create()
.WithBody("1 : WireMock.Net !")
);
server.Given(Request.Create()
.WithPath("/test2")
.UsingAnyMethod()
).RespondWith(Response.Create()
.WithBody("2 : WireMock.Net !")
);
}, true);
}
var app = builder.Build();
app.MapGet("/weatherforecast", async (HttpClient client) =>
{
var result = await client.GetStringAsync("https://real-api:12345/test1");
return Enumerable.Range(1, 3).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
result
));
});
app.MapGet("/weatherforecast2", async (IHttpClientFactory factory) =>
{
using var client = factory.CreateClient();
var result = await client.GetStringAsync("https://real-api:12345/test2");
return Enumerable.Range(1, 3).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
result
));
});
await app.RunAsync();

View File

@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:57375",
"sslPort": 44333
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5112",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:7021;http://localhost:5112",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,4 @@
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.AspNetCore.Middleware\WireMock.Net.AspNetCore.Middleware.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -89,7 +89,7 @@ public class MappingModel
/// <summary>
/// Data Object which can be used when WithTransformer is used.
/// e.g. lookup an path in this object using
/// e.g. lookup a path in this object using
/// <example>
/// lookup data "1"
/// </example>
@@ -105,4 +105,9 @@ public class MappingModel
/// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional]
/// </summary>
public string? ProtoDefinition { get; set; }
/// <summary>
/// The Grpc ProtoDefinitions which are used for this mapping (request and response). [Optional]
/// </summary>
public string[]? ProtoDefinitions { get; set; }
}

View File

@@ -137,6 +137,11 @@ public class ResponseModel
/// </summary>
public string? ProtoDefinition { get; set; }
/// <summary>
/// Gets or sets the proto definitions.
/// </summary>
public string[]? ProtoDefinitions { get; set; }
/// <summary>
/// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".
/// </summary>

View File

@@ -121,7 +121,7 @@ public class SettingsModel
/// <summary>
/// A list of Grpc ProtoDefinitions which can be used.
/// </summary>
public Dictionary<string, string>? ProtoDefinitions { get; set; }
public Dictionary<string, string[]>? ProtoDefinitions { get; set; }
#if NETSTANDARD1_3_OR_GREATER || NET461
/// <summary>

View File

@@ -51,10 +51,10 @@ public interface IWireMockLogger
/// <summary>
/// Writes the message at the Error level using the specified exception.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="message">The message.</param>
/// <param name="exception">The exception.</param>
[PublicAPI]
void Error(string formatString, Exception exception);
void Error(string message, Exception exception);
/// <summary>
/// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more).

View File

@@ -79,7 +79,7 @@ public interface IBodyData
/// <summary>
/// Gets or sets the proto definition.
/// </summary>
public Func<IdOrText>? ProtoDefinition { get; set; }
public Func<IdOrTexts>? ProtoDefinition { get; set; }
/// <summary>
/// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".

View File

@@ -0,0 +1,25 @@
// Copyright © WireMock.Net
using WireMock.Types;
// ReSharper disable once CheckNamespace
namespace WireMock.Util;
// ReSharper disable once InconsistentNaming
public static class IBodyDataExtensions
{
public static BodyType GetBodyType(this IBodyData bodyData)
{
if (bodyData.DetectedBodyTypeFromContentType is not null and not BodyType.None)
{
return bodyData.DetectedBodyTypeFromContentType.Value;
}
if (bodyData.DetectedBodyType is not null and not BodyType.None)
{
return bodyData.DetectedBodyType.Value;
}
return BodyType.None;
}
}

View File

@@ -1,35 +0,0 @@
// Copyright © WireMock.Net
namespace WireMock.Models;
/// <summary>
/// A structure defining an (optional) Id and a Text.
/// </summary>
public readonly struct IdOrText
{
/// <summary>
/// The Id [optional].
/// </summary>
public string? Id { get; }
/// <summary>
/// The Text.
/// </summary>
public string Text { get; }
/// <summary>
/// When Id is defined, return the Id, else the Text.
/// </summary>
public string Value => Id ?? Text;
/// <summary>
/// Create a IdOrText
/// </summary>
/// <param name="id">The Id [optional]</param>
/// <param name="text">The Text.</param>
public IdOrText(string? id, string text)
{
Id = id;
Text = text;
}
}

View File

@@ -0,0 +1,59 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
namespace WireMock.Models;
/// <summary>
/// A structure defining an (optional) Id and a Text.
/// </summary>
public readonly struct IdOrTexts
{
/// <summary>
/// The Id [optional].
/// </summary>
public string? Id { get; }
/// <summary>
/// The Text.
/// </summary>
public IReadOnlyList<string> Texts { get; }
/// <summary>
/// Create a IdOrText
/// </summary>
/// <param name="id">The Id [optional]</param>
/// <param name="text">The Text.</param>
public IdOrTexts(string? id, string text) : this(id, [text])
{
}
/// <summary>
/// Create a IdOrText
/// </summary>
/// <param name="id">The Id [optional]</param>
/// <param name="texts">The Texts.</param>
public IdOrTexts(string? id, IReadOnlyList<string> texts)
{
Id = id;
Texts = texts;
}
/// <summary>
/// When Id is defined, return process the Id, else process the Texts.
/// </summary>
/// <param name="id">Callback to process the id.</param>
/// <param name="texts">Callback to process the texts.</param>
public void Value(Action<string> id, Action<IReadOnlyList<string>> texts)
{
if (Id != null)
{
id(Id);
}
else
{
texts(Texts);
}
}
}

View File

@@ -4,7 +4,7 @@
<Description>Commonly used models, enumerations and types.</Description>
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;net451;net461;netstandard1.0;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net45;net451;net461;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591;8603</NoWarn>
<AssemblyName>WireMock.Net.Abstractions</AssemblyName>
@@ -36,15 +36,18 @@
<ItemGroup>
<!-- See also https://mstack.nl/blog/20210801-source-generators -->
<PackageReference Include="FluentBuilder" Version="0.9.0">
<PackageReference Include="FluentBuilder" Version="0.10.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.14.0">
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- CVE-2018-8292 -->
<PackageReference Include="System.Net.Http " Version="4.3.4" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetFramework)' != 'netstandard1.0'">

View File

@@ -0,0 +1,9 @@
// Copyright © WireMock.Net
namespace WireMock.Net.AspNetCore.Middleware;
internal static class AppConstants
{
internal const string HEADER_REDIRECT = "X-WireMock-Redirect";
internal const string HEADER_RESPONSE_DELAY = "X-WireMock-Response-Delay";
}

View File

@@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Stef.Validation;
using WireMock.Server;
namespace WireMock.Net.AspNetCore.Middleware.HttpDelegatingHandler;
/// <summary>
/// DelegatingHandler that takes requests made via the <see cref="HttpClient"/>
/// and routes them to the <see cref="WireMockServer"/>.
/// </summary>
internal class WireMockDelegationHandler : DelegatingHandler
{
private readonly ILogger<WireMockDelegationHandler> _logger;
private readonly WireMockServerInstance _server;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly WireMockDelegationHandlerSettings _settings;
/// <summary>
/// Creates a new instance of <see cref="WireMockDelegationHandler"/>
/// </summary>
public WireMockDelegationHandler(
ILogger<WireMockDelegationHandler> logger,
WireMockServerInstance server,
IHttpContextAccessor httpContextAccessor,
WireMockDelegationHandlerSettings settings
)
{
_server = Guard.NotNull(server);
_httpContextAccessor = Guard.NotNull(httpContextAccessor);
_logger = Guard.NotNull(logger);
_settings = Guard.NotNull(settings);
}
/// <inheritdoc />
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Guard.NotNull(request);
Guard.NotNull(_httpContextAccessor.HttpContext);
if (_settings.AlwaysRedirect || IsWireMockRedirectHeaderSetToTrue())
{
_logger.LogDebug("Redirecting request to WireMock server");
if (_server.Instance?.Url != null)
{
request.RequestUri = new Uri(_server.Instance.Url + request.RequestUri!.PathAndQuery);
}
}
if (TryGetDelayHeaderValue(out var delayInMs))
{
await Task.Delay(delayInMs, cancellationToken);
}
return await base.SendAsync(request, cancellationToken);
}
private bool IsWireMockRedirectHeaderSetToTrue()
{
return
_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_REDIRECT, out var values) &&
bool.TryParse(values.ToString(), out var shouldRedirectToWireMock) && shouldRedirectToWireMock;
}
private bool TryGetDelayHeaderValue(out int delayInMs)
{
delayInMs = 0;
return
_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_RESPONSE_DELAY, out var values) &&
int.TryParse(values.ToString(), out delayInMs);
}
}

View File

@@ -0,0 +1,8 @@
// Copyright © WireMock.Net
namespace WireMock.Net.AspNetCore.Middleware.HttpDelegatingHandler;
internal class WireMockDelegationHandlerSettings
{
public bool AlwaysRedirect { get; set; }
}

View File

@@ -0,0 +1,52 @@
// Copyright © WireMock.Net
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;
using Stef.Validation;
using WireMock.Net.AspNetCore.Middleware.HttpDelegatingHandler;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.AspNetCore.Middleware;
/// <summary>
/// Extension methods for <see cref="IServiceCollection"/>.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds all the components necessary to run WireMock.Net as a background service.
/// </summary>
public static IServiceCollection AddWireMockService(
this IServiceCollection services,
Action<WireMockServer> configure,
bool alwaysRedirectToWireMock = true,
WireMockServerSettings? settings = null
)
{
Guard.NotNull(services);
Guard.NotNull(configure);
services.AddTransient<WireMockDelegationHandler>();
services.AddSingleton(new WireMockServerInstance(configure, settings));
services.AddSingleton(new WireMockDelegationHandlerSettings
{
AlwaysRedirect = alwaysRedirectToWireMock
});
services.AddHostedService<WireMockBackgroundService>();
services.AddHttpClient();
services.AddHttpContextAccessor();
services.ConfigureAll<HttpClientFactoryOptions>(options =>
{
options.HttpMessageHandlerBuilderActions.Add(builder =>
{
builder.AdditionalHandlers.Add(builder.Services.GetRequiredService<WireMockDelegationHandler>());
});
});
return services;
}
}

View File

@@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Middleware which can be used to host WireMock.Net as a Middleware background process in a AspNetCore WebApplication</Description>
<AssemblyTitle>WireMock.Net.AspNetCore.Middleware</AssemblyTitle>
<Authors>Matthew Yost;Stef Heyenrath</Authors>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.AspNetCore.Middleware</AssemblyName>
<PackageId>WireMock.Net.AspNetCore.Middleware</PackageId>
<PackageTags>dotnet;middleware;wiremock;service;webapplication;aspnetcore</PackageTags>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A13}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<None Remove="../../resources/WireMock.Net-Logo.png" />
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,39 @@
// Copyright © WireMock.Net
using Microsoft.Extensions.Hosting;
using Stef.Validation;
using WireMock.Server;
namespace WireMock.Net.AspNetCore.Middleware;
/// <summary>
/// A <see cref="BackgroundService"/> used to start/stop the <see cref="WireMockServer"/>
/// </summary>
internal class WireMockBackgroundService : BackgroundService
{
private readonly WireMockServerInstance _serverInstance;
/// <summary>
/// Creates a new <see cref="BackgroundService"/> using an instance
/// of <see cref="WireMockServerInstance"/>
/// </summary>
/// <param name="serverInstance"></param>
public WireMockBackgroundService(WireMockServerInstance serverInstance)
{
_serverInstance = Guard.NotNull(serverInstance);
}
/// <inheritdoc />
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_serverInstance.Start();
return Task.CompletedTask;
}
/// <inheritdoc />
public override Task StopAsync(CancellationToken cancellationToken)
{
_serverInstance.Stop();
return base.StopAsync(cancellationToken);
}
}

View File

@@ -0,0 +1,49 @@
// Copyright © WireMock.Net
using Stef.Validation;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.AspNetCore.Middleware;
/// <summary>
/// WireMockServer Instance object
/// </summary>
internal class WireMockServerInstance
{
private readonly Action<WireMockServer> _configureAction;
private readonly WireMockServerSettings? _settings;
/// <summary>
/// Creates a new instance and provides ability to add configuration
/// for the start method of <see cref="WireMockServer"/>
/// </summary>
public WireMockServerInstance(Action<WireMockServer> configure, WireMockServerSettings? settings = null)
{
_configureAction = Guard.NotNull(configure);
_settings = settings;
}
/// <summary>
/// Instance accessor for the <see cref="WireMockServer" />
/// </summary>
public WireMockServer? Instance { get; private set; }
/// <summary>
/// Configures and starts <see cref="WireMockServer"/> instance for use.
/// </summary>
public void Start()
{
Instance = _settings != null ? WireMockServer.Start(_settings) : WireMockServer.Start();
_configureAction.Invoke(Instance);
}
/// <summary>
/// Stops the <see cref="WireMockServer"/>
/// </summary>
public void Stop()
{
Instance?.Stop();
}
}

View File

@@ -0,0 +1,14 @@
// Copyright © WireMock.Net
using Aspire.Hosting.ApplicationModel;
namespace WireMock.Net.Aspire.Extensions;
internal static class ResourceLoggerServiceExtensions
{
public static void SetLogger(this ResourceLoggerService resourceLoggerService, WireMockServerResource wireMockServerResource)
{
var logger = resourceLoggerService.GetLogger(wireMockServerResource);
wireMockServerResource.SetLogger(logger);
}
}

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.0.1-preview-05</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
@@ -31,13 +30,16 @@
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Aspire.Hosting" Version="8.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -50,7 +50,7 @@ public class WireMockServerArguments
///
/// Default value is <c>false</c>.
/// </summary>
public bool WithWatchStaticMappings { get; set; }
public bool WatchStaticMappings { get; set; }
/// <summary>
/// Specifies the path for the (static) mapping json files.
@@ -65,7 +65,7 @@ public class WireMockServerArguments
/// <summary>
/// Optional delegate that will be invoked to configure the WireMock.Net resource using the <see cref="AdminApiMappingBuilder"/>.
/// </summary>
public Func<AdminApiMappingBuilder, Task>? ApiMappingBuilder { get; set; }
public Func<AdminApiMappingBuilder, CancellationToken, Task>? ApiMappingBuilder { get; set; }
/// <summary>
/// Converts the current instance's properties to an array of command-line arguments for starting the WireMock.Net server.
@@ -88,7 +88,7 @@ public class WireMockServerArguments
Add(args, "--ReadStaticMappings", "true");
}
if (WithWatchStaticMappings)
if (WatchStaticMappings)
{
Add(args, "--ReadStaticMappings", "true");
Add(args, "--WatchStaticMappings", "true");

View File

@@ -112,7 +112,7 @@ public static class WireMockServerBuilderExtensions
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WithWatchStaticMappings = true;
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}
@@ -124,8 +124,10 @@ public static class WireMockServerBuilderExtensions
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
return Guard.NotNull(wiremock)
.WithBindMount(Guard.NotNullOrWhiteSpace(mappingsPath), DefaultLinuxMappingsPath);
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;
return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}
/// <summary>
@@ -151,6 +153,17 @@ public static class WireMockServerBuilderExtensions
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);

View File

@@ -3,50 +3,39 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Microsoft.Extensions.Logging;
using RestEase;
using WireMock.Client;
using WireMock.Client.Extensions;
namespace WireMock.Net.Aspire;
internal class WireMockServerLifecycleHook(ResourceLoggerService loggerService) : IDistributedApplicationLifecycleHook
internal class WireMockServerLifecycleHook(ILoggerFactory loggerFactory) : IDistributedApplicationLifecycleHook, IAsyncDisposable
{
private readonly CancellationTokenSource _shutdownCts = new();
public async Task AfterResourcesCreatedAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(_shutdownCts.Token, cancellationToken);
var wireMockServerResources = appModel.Resources
.OfType<WireMockServerResource>()
.Where(resource => resource.Arguments.ApiMappingBuilder is not null)
.ToArray();
if (wireMockServerResources.Length == 0)
{
return;
}
foreach (var wireMockServerResource in wireMockServerResources)
{
wireMockServerResource.SetLogger(loggerFactory.CreateLogger<WireMockServerResource>());
var endpoint = wireMockServerResource.GetEndpoint();
if (endpoint.IsAllocated)
{
var adminApi = CreateWireMockAdminApi(wireMockServerResource);
await wireMockServerResource.WaitForHealthAsync(cts.Token);
var logger = loggerService.GetLogger(wireMockServerResource);
logger.LogInformation("Checking Health status from WireMock.Net");
await wireMockServerResource.CallApiMappingBuilderActionAsync(cts.Token);
await adminApi.WaitForHealthAsync(cancellationToken: cancellationToken);
logger.LogInformation("Calling ApiMappingBuilder to add mappings to WireMock.Net");
var mappingBuilder = adminApi.GetMappingBuilder();
await wireMockServerResource.Arguments.ApiMappingBuilder!.Invoke(mappingBuilder);
wireMockServerResource.StartWatchingStaticMappings(cts.Token);
}
}
}
private static IWireMockAdminApi CreateWireMockAdminApi(WireMockServerResource resource)
public async ValueTask DisposeAsync()
{
var adminApi = RestClient.For<IWireMockAdminApi>(resource.GetEndpoint().Url);
return resource.Arguments.HasBasicAuthentication ?
adminApi.WithAuthorization(resource.Arguments.AdminUsername!, resource.Arguments.AdminPassword!) :
adminApi;
await _shutdownCts.CancelAsync();
}
}

View File

@@ -1,6 +1,11 @@
// Copyright © WireMock.Net
using Microsoft.Extensions.Logging;
using RestEase;
using Stef.Validation;
using WireMock.Client;
using WireMock.Client.Extensions;
using WireMock.Util;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting.ApplicationModel;
@@ -10,7 +15,13 @@ namespace Aspire.Hosting.ApplicationModel;
/// </summary>
public class WireMockServerResource : ContainerResource, IResourceWithServiceDiscovery
{
private const int EnhancedFileSystemWatcherTimeoutMs = 2000;
internal WireMockServerArguments Arguments { get; }
internal Lazy<IWireMockAdminApi> AdminApi => new(CreateWireMockAdminApi);
private ILogger? _logger;
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
/// <summary>
/// Initializes a new instance of the <see cref="WireMockServerResource"/> class.
@@ -30,4 +41,82 @@ public class WireMockServerResource : ContainerResource, IResourceWithServiceDis
{
return new EndpointReference(this, "http");
}
internal void SetLogger(ILogger logger)
{
_logger = logger;
}
internal async Task WaitForHealthAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("Checking Health status from WireMock.Net");
await AdminApi.Value.WaitForHealthAsync(cancellationToken: cancellationToken);
}
internal async Task CallApiMappingBuilderActionAsync(CancellationToken cancellationToken)
{
if (Arguments.ApiMappingBuilder == null)
{
return;
}
_logger?.LogInformation("Calling ApiMappingBuilder to add mappings to WireMock.Net");
var mappingBuilder = AdminApi.Value.GetMappingBuilder();
await Arguments.ApiMappingBuilder.Invoke(mappingBuilder, cancellationToken);
}
internal void StartWatchingStaticMappings(CancellationToken cancellationToken)
{
if (!Arguments.WatchStaticMappings || string.IsNullOrEmpty(Arguments.MappingsPath))
{
return;
}
cancellationToken.Register(() =>
{
if (_enhancedFileSystemWatcher != null)
{
_enhancedFileSystemWatcher.EnableRaisingEvents = false;
_enhancedFileSystemWatcher.Created -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Changed -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Deleted -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Dispose();
_enhancedFileSystemWatcher = null;
}
});
_logger?.LogInformation("Starting to watch static mappings on path: '{Path}'. ", Arguments.MappingsPath);
_enhancedFileSystemWatcher = new EnhancedFileSystemWatcher(Arguments.MappingsPath, "*.json", EnhancedFileSystemWatcherTimeoutMs)
{
IncludeSubdirectories = true
};
_enhancedFileSystemWatcher.Created += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Changed += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Deleted += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.EnableRaisingEvents = true;
}
private IWireMockAdminApi CreateWireMockAdminApi()
{
var adminApi = RestClient.For<IWireMockAdminApi>(GetEndpoint().Url);
return Arguments.HasBasicAuthentication ?
adminApi.WithAuthorization(Arguments.AdminUsername!, Arguments.AdminPassword!) :
adminApi;
}
private async void FileCreatedChangedOrDeleted(object sender, FileSystemEventArgs args)
{
_logger?.LogInformation("MappingFile created, changed or deleted: '{0}'. Triggering ReloadStaticMappings.", args.FullPath);
try
{
await AdminApi.Value.ReloadStaticMappingsAsync();
}
catch (Exception ex)
{
_logger?.LogWarning(ex, "Error calling /__admin/mappings/reloadStaticMappings");
}
}
}

View File

@@ -0,0 +1,59 @@
overview
```mermaid
classDiagram
class WireMockServerResource {
}
class ContainerResource {
}
class IResourceWithServiceDiscovery {
}
class IResourceWithEndpoints {
}
class WireMockServerArguments {
}
class EndpointReference {
}
class AdminApiMappingBuilder {
}
class IWireMockAdminApi {
}
class MappingModelBuilder {
}
class WireMockServerLifecycleHook {
}
class ResourceLoggerService {
}
class DistributedApplicationModel {
}
class IDistributedApplicationLifecycleHook {
}
WireMockServerResource --> ContainerResource : Inherits
WireMockServerResource --> IResourceWithServiceDiscovery : Implements
WireMockServerResource --> WireMockServerArguments : Uses
WireMockServerResource --> EndpointReference : Returns
WireMockServerArguments --> AdminApiMappingBuilder : Uses
AdminApiMappingBuilder --> MappingModelBuilder : Uses
AdminApiMappingBuilder --> IWireMockAdminApi : Uses
IResourceWithServiceDiscovery --> IResourceWithEndpoints : Inherits
WireMockServerLifecycleHook --> IDistributedApplicationLifecycleHook : Implements
WireMockServerLifecycleHook --> ResourceLoggerService : Uses
WireMockServerLifecycleHook --> DistributedApplicationModel : Uses
WireMockServerLifecycleHook --> WireMockServerResource : Uses
WireMockServerLifecycleHook --> IWireMockAdminApi : Uses
```

View File

@@ -10,6 +10,7 @@ using Stef.Validation;
using WireMock.Exceptions;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -92,6 +93,17 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private bool IsMatch(dynamic input, string pattern)
{
var isMatchWithString = input is string;

View File

@@ -43,7 +43,7 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'">
<PackageReference Include="CS-Script" Version="4.8.13" />
<PackageReference Include="CS-Script" Version="4.8.17" />
</ItemGroup>
</Project>

View File

@@ -26,7 +26,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="RamlToOpenApiConverter" Version="0.6.1" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.17" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
</ItemGroup>

View File

@@ -72,7 +72,7 @@ public static class WireMockAdminApiExtensions
if (retries >= MaxRetries)
{
throw new InvalidOperationException($"The /__admin/health endpoint did not return 'Healthy' after {MaxRetries} retries and {totalWaitTime / 1000.0:0.0} seconds.");
throw new InvalidOperationException($"The /__admin/health endpoint did not return '{HealthStatusHealthy}' after {MaxRetries} retries and {totalWaitTime / 1000.0:0.0} seconds.");
}
}

View File

@@ -122,6 +122,13 @@ public interface IWireMockAdminApi
[Post("mappings/reset")]
Task<StatusModel> ResetMappingsAsync(bool? reloadStaticMappings = false, CancellationToken cancellationToken = default);
/// <summary>
/// Reload the static mappings.
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("mappings/reloadStaticMappings")]
Task<StatusModel> ReloadStaticMappingsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Get a mapping based on the guid
/// </summary>

View File

@@ -4,7 +4,7 @@
<Description>A RestClient using RestEase to access the admin interface.</Description>
<AssemblyTitle>WireMock.Net.RestClient</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;netstandard1.1;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net45;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.RestClient</AssemblyName>
<PackageId>WireMock.Net.RestClient</PackageId>
@@ -30,8 +30,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.3.0" />
<PackageReference Include="RestEase" Version="1.5.7" />
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.7.0" />
<PackageReference Include="RestEase" Version="1.6.4" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
</ItemGroup>

View File

@@ -0,0 +1,80 @@
// Copyright © WireMock.Net
using System;
using Newtonsoft.Json;
using Stef.Validation;
using TUnit.Core.Logging;
using WireMock.Admin.Requests;
using WireMock.Logging;
namespace WireMock.Net.TUnit;
/// <summary>
/// When using TUnit, this class enables to log the output from WireMock.Net to the <see cref="TUnitLogger"/>.
/// </summary>
// ReSharper disable once InconsistentNaming
public sealed class TUnitWireMockLogger : IWireMockLogger
{
private readonly TUnitLogger _tUnitLogger;
/// <summary>
/// Create a new instance on the <see cref="TUnitWireMockLogger"/>.
/// </summary>
/// <param name="tUnitLogger">Represents a class which can be used to provide test output.</param>
public TUnitWireMockLogger(TUnitLogger tUnitLogger)
{
_tUnitLogger = Guard.NotNull(tUnitLogger);
}
/// <inheritdoc />
public void Debug(string formatString, params object[] args)
{
_tUnitLogger.LogDebug(Format("Debug", formatString, args));
}
/// <inheritdoc />
public void Info(string formatString, params object[] args)
{
_tUnitLogger.LogInformation(Format("Info", formatString, args));
}
/// <inheritdoc />
public void Warn(string formatString, params object[] args)
{
_tUnitLogger.LogWarning(Format("Warning", formatString, args));
}
/// <inheritdoc />
public void Error(string formatString, params object[] args)
{
_tUnitLogger.LogError(Format("Error", formatString, args));
}
/// <inheritdoc />
public void Error(string formatString, Exception exception)
{
_tUnitLogger.LogError(Format("Error", formatString, exception.Message), exception);
if (exception is AggregateException ae)
{
ae.Handle(ex =>
{
_tUnitLogger.LogError(Format("Error", "Exception {0}", ex.Message), exception);
return true;
});
}
}
/// <inheritdoc />
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
var message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
_tUnitLogger.LogDebug(Format("DebugRequestResponse", "Admin[{0}] {1}", isAdminRequest, message));
}
private static string Format(string level, string formatString, params object[] args)
{
var message = args.Length > 0 ? string.Format(formatString, args) : formatString;
return $"{DateTime.UtcNow} [{level}] : {message}";
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Some extensions for TUnit (TUnitLogger)</Description>
<AssemblyTitle>WireMock.Net.TUnit</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net8.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.TUnit</AssemblyName>
<RootNamespace>WireMock.Net.Tunit</RootNamespace>
<PackageId>WireMock.Net.TUnit</PackageId>
<PackageTags>tdd;wiremock;test;unittest;TUnit</PackageTags>
<ProjectGuid>{0DE0954F-8C00-4E8D-B94A-4361FC1CB34A}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
<PackageReference Include="TUnit.Core" Version="0.2.195" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,16 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.Runtime.InteropServices;
using WireMock.Net.Testcontainers.Models;
namespace WireMock.Net.Testcontainers.Utils;
internal static class ContainerInfoProvider
{
public static readonly Dictionary<OSPlatform, ContainerInfo> Info = new()
{
{ OSPlatform.Linux, new ContainerInfo("sheyenrath/wiremock.net-alpine", "/app/__admin/mappings") },
{ OSPlatform.Windows, new ContainerInfo("sheyenrath/wiremock.net-windows", @"c:\app\__admin\mappings") }
};
}

View File

@@ -0,0 +1,25 @@
// Copyright © WireMock.Net
using System;
using System.Runtime.InteropServices;
using DotNet.Testcontainers.Configurations;
using System.Threading.Tasks;
namespace WireMock.Net.Testcontainers.Utils;
internal static class ContainerUtils
{
public static Lazy<Task<OSPlatform>> GetImageOSAsync = new(async () =>
{
if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null)
{
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
}
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
using var dockerClient = dockerClientConfig.CreateClient();
var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
});
}

View File

@@ -20,6 +20,7 @@
<ItemGroup>
<Compile Include="..\WireMock.Net\Http\HttpClientFactory2.cs" Link="Http\HttpClientFactory2.cs" />
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<ItemGroup>
@@ -28,7 +29,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Stef.Validation" Version="0.1.1" />
<PackageReference Include="Testcontainers" Version="[3.9.0]" />
<PackageReference Include="Testcontainers" Version="4.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -16,6 +16,12 @@ public sealed class WireMockConfiguration : ContainerConfiguration
public string? Password { get; }
public string? StaticMappingsPath { get; private set; }
public bool WatchStaticMappings { get; private set; }
public bool WatchStaticMappingsInSubdirectories { get; private set; }
public bool HasBasicAuthentication => !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
public WireMockConfiguration(string? username = null, string? password = null)
@@ -61,5 +67,31 @@ public sealed class WireMockConfiguration : ContainerConfiguration
{
Username = BuildConfiguration.Combine(oldValue.Username, newValue.Username);
Password = BuildConfiguration.Combine(oldValue.Password, newValue.Password);
StaticMappingsPath = BuildConfiguration.Combine(oldValue.StaticMappingsPath, newValue.StaticMappingsPath);
WatchStaticMappings = BuildConfiguration.Combine(oldValue.WatchStaticMappings, newValue.WatchStaticMappings);
WatchStaticMappingsInSubdirectories = BuildConfiguration.Combine(oldValue.WatchStaticMappingsInSubdirectories, newValue.WatchStaticMappingsInSubdirectories);
}
/// <summary>
/// Set the StaticMappingsPath.
/// </summary>
/// <param name="path">The path which contains the StaticMappings.</param>
/// <returns><see cref="WireMockConfiguration"/></returns>
public WireMockConfiguration WithStaticMappingsPath(string path)
{
StaticMappingsPath = path;
return this;
}
/// <summary>
/// Watch the static mappings.
/// </summary>
/// <param name="includeSubDirectories">Also look in SubDirectories.</param>
/// <returns><see cref="WireMockConfiguration"/></returns>
public WireMockConfiguration WithWatchStaticMappings(bool includeSubDirectories)
{
WatchStaticMappings = true;
WatchStaticMappingsInSubdirectories = includeSubDirectories;
return this;
}
}

View File

@@ -1,14 +1,20 @@
// Copyright © WireMock.Net
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using RestEase;
using Stef.Validation;
using WireMock.Client;
using WireMock.Client.Extensions;
using WireMock.Http;
using WireMock.Net.Testcontainers.Utils;
using WireMock.Util;
namespace WireMock.Net.Testcontainers;
@@ -17,17 +23,23 @@ namespace WireMock.Net.Testcontainers;
/// </summary>
public sealed class WireMockContainer : DockerContainer
{
private const int EnhancedFileSystemWatcherTimeoutMs = 2000;
internal const int ContainerPort = 80;
private readonly WireMockConfiguration _configuration;
private IWireMockAdminApi? _adminApi;
private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher;
/// <summary>
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
public WireMockContainer(WireMockConfiguration configuration) : base(configuration)
{
_configuration = Guard.NotNull(configuration);
_configuration = Stef.Validation.Guard.NotNull(configuration);
Started += WireMockContainer_Started;
}
/// <summary>
@@ -92,6 +104,71 @@ public sealed class WireMockContainer : DockerContainer
return client;
}
/// <summary>
/// Copies a test host directory or file to the container and triggers a reload of the static mappings if required.
/// </summary>
/// <param name="source">The source directory or file to be copied.</param>
/// <param name="target">The target directory path to copy the files to.</param>
/// <param name="fileMode">The POSIX file mode permission.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>A task that completes when the directory or file has been copied.</returns>
public new async Task CopyAsync(string source, string target, UnixFileModes fileMode = Unix.FileMode644, CancellationToken ct = default)
{
await base.CopyAsync(source, target, fileMode, ct);
if (_configuration.WatchStaticMappings && await PathStartsWithContainerMappingsPath(target))
{
await ReloadStaticMappingsAsync(target, ct);
}
}
/// <summary>
/// Reload the static mappings.
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
public async Task ReloadStaticMappingsAsync(CancellationToken cancellationToken = default)
{
if (_adminApi == null)
{
return;
}
try
{
await _adminApi.ReloadStaticMappingsAsync(cancellationToken);
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Error calling /__admin/mappings/reloadStaticMappings");
}
}
/// <inheritdoc />
protected override ValueTask DisposeAsyncCore()
{
if (_enhancedFileSystemWatcher != null)
{
_enhancedFileSystemWatcher.EnableRaisingEvents = false;
_enhancedFileSystemWatcher.Created -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Changed -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Deleted -= FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Dispose();
_enhancedFileSystemWatcher = null;
}
Started -= WireMockContainer_Started;
return base.DisposeAsyncCore();
}
private static async Task<bool> PathStartsWithContainerMappingsPath(string value)
{
var imageOs = await ContainerUtils.GetImageOSAsync.Value;
return value.StartsWith(ContainerInfoProvider.Info[imageOs].MappingsPath);
}
private void ValidateIfRunning()
{
if (State != TestcontainersStates.Running)
@@ -100,5 +177,35 @@ public sealed class WireMockContainer : DockerContainer
}
}
private void WireMockContainer_Started(object sender, EventArgs e)
{
_adminApi = CreateWireMockAdminClient();
if (!_configuration.WatchStaticMappings || string.IsNullOrEmpty(_configuration.StaticMappingsPath))
{
return;
}
_enhancedFileSystemWatcher = new EnhancedFileSystemWatcher(_configuration.StaticMappingsPath!, "*.json", EnhancedFileSystemWatcherTimeoutMs)
{
IncludeSubdirectories = _configuration.WatchStaticMappingsInSubdirectories
};
_enhancedFileSystemWatcher.Created += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Changed += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.Deleted += FileCreatedChangedOrDeleted;
_enhancedFileSystemWatcher.EnableRaisingEvents = true;
}
private async void FileCreatedChangedOrDeleted(object sender, FileSystemEventArgs args)
{
await ReloadStaticMappingsAsync(args.FullPath);
}
private async Task ReloadStaticMappingsAsync(string path, CancellationToken cancellationToken = default)
{
Logger.LogInformation("MappingFile created, changed or deleted: '{Path}'. Triggering ReloadStaticMappings.", path);
await ReloadStaticMappingsAsync(cancellationToken);
}
private Uri GetPublicUri() => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ContainerPort)).Uri;
}

View File

@@ -1,14 +1,13 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Net.Testcontainers.Models;
using WireMock.Net.Testcontainers.Utils;
namespace WireMock.Net.Testcontainers;
@@ -17,27 +16,8 @@ namespace WireMock.Net.Testcontainers;
/// </summary>
public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContainerBuilder, WireMockContainer, WireMockConfiguration>
{
private readonly Dictionary<bool, ContainerInfo> _info = new()
{
{ false, new ContainerInfo("sheyenrath/wiremock.net:latest", "/app/__admin/mappings") },
{ true, new ContainerInfo("sheyenrath/wiremock.net-windows:latest", @"c:\app\__admin\mappings") }
};
private const string DefaultLogger = "WireMockConsoleLogger";
private readonly Lazy<Task<bool>> _isWindowsAsLazy = new(async () =>
{
if (TestcontainersSettings.OS.DockerEndpointAuthConfig == null)
{
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
}
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
using var dockerClient = dockerClientConfig.CreateClient();
var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) > -1;
});
private OSPlatform? _imageOS;
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
@@ -48,14 +28,36 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
}
/// <summary>
/// Automatically set the correct image (Linux or Windows) for WireMock which to create the container.
/// Automatically use the correct image for WireMock.
/// For Linux this is "sheyenrath/wiremock.net-alpine:latest"
/// For Windows this is "sheyenrath/wiremock.net-windows:latest"
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithImage()
{
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
return WithImage(_info[isWindows].Image);
_imageOS ??= ContainerUtils.GetImageOSAsync.Value.GetAwaiter().GetResult();
return WithImage(_imageOS.Value);
}
/// <summary>
/// Automatically use a Linux image for WireMock. This is "sheyenrath/wiremock.net-alpine:latest"
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithLinuxImage()
{
return WithImage(OSPlatform.Linux);
}
/// <summary>
/// Automatically use a Windows image for WireMock. This is "sheyenrath/wiremock.net-windows:latest"
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithWindowsImage()
{
return WithImage(OSPlatform.Windows);
}
/// <summary>
@@ -106,7 +108,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
[PublicAPI]
public WireMockContainerBuilder WithWatchStaticMappings(bool includeSubDirectories)
{
return WithCommand("--WatchStaticMappings true").WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
return Merge(DockerResourceConfiguration, DockerResourceConfiguration.WithWatchStaticMappings(includeSubDirectories))
.WithCommand("--WatchStaticMappings true")
.WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
}
/// <summary>
@@ -120,11 +124,9 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{
Guard.NotNullOrEmpty(path);
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
return WithReadStaticMappings()
.WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}")
.WithBindMount(path, _info[isWindows].MappingsPath);
return Merge(DockerResourceConfiguration, DockerResourceConfiguration.WithStaticMappingsPath(path))
.WithReadStaticMappings()
.WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
}
private WireMockContainerBuilder(WireMockConfiguration dockerResourceConfiguration) : base(dockerResourceConfiguration)
@@ -138,9 +140,33 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
/// <inheritdoc />
public override WireMockContainer Build()
{
Validate();
var builder = this;
return new WireMockContainer(DockerResourceConfiguration);
// In case no image has been set, set the image using internal logic.
if (DockerResourceConfiguration.Image == null)
{
builder = WithImage();
}
// In case the _imageOS is not set, determine it from the Image FullName.
if (_imageOS == null)
{
if (builder.DockerResourceConfiguration.Image.FullName.IndexOf("wiremock.net", StringComparison.OrdinalIgnoreCase) < 0)
{
throw new InvalidOperationException();
}
_imageOS = builder.DockerResourceConfiguration.Image.FullName.IndexOf("windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
}
if (!string.IsNullOrEmpty(builder.DockerResourceConfiguration.StaticMappingsPath))
{
builder = builder.WithBindMount(builder.DockerResourceConfiguration.StaticMappingsPath, ContainerInfoProvider.Info[_imageOS.Value].MappingsPath);
}
builder.Validate();
return new WireMockContainer(builder.DockerResourceConfiguration);
}
/// <inheritdoc />
@@ -148,18 +174,11 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{
var builder = base.Init();
// In case no image has been set, set the image using internal logic.
if (builder.DockerResourceConfiguration.Image == null)
{
builder = builder.WithImage();
}
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
var waitForContainerOS = isWindows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
var waitForContainerOS = _imageOS == OSPlatform.Windows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
return builder
.WithPortBinding(WireMockContainer.ContainerPort, true)
.WithCommand($"--WireMockLogger {DefaultLogger}")
.WithWaitStrategy(waitForContainerOS.UntilMessageIsLogged("By Stef Heyenrath"));
.WithWaitStrategy(waitForContainerOS.UntilMessageIsLogged("WireMock.Net server running"));
}
/// <inheritdoc />
@@ -179,4 +198,10 @@ public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContaine
{
return new WireMockContainerBuilder(new WireMockConfiguration(oldValue, newValue));
}
private WireMockContainerBuilder WithImage(OSPlatform os)
{
_imageOS = os;
return WithImage(ContainerInfoProvider.Info[os].Image);
}
}

View File

@@ -73,8 +73,6 @@ public sealed class TestOutputHelperWireMockLogger : IWireMockLogger
private static string Format(string level, string formatString, params object[] args)
{
Guard.NotNull(formatString);
var message = args.Length > 0 ? string.Format(formatString, args) : formatString;
return $"{DateTime.UtcNow} [{level}] : {message}";
}

View File

@@ -3,7 +3,7 @@
<Description>Some extensions for xUnit (ITestOutputHelper)</Description>
<AssemblyTitle>WireMock.Net.xUnit</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;net451;netstandard1.0;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net45;net451;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.xUnit</AssemblyName>
<RootNamespace>WireMock.Net.Xunit</RootNamespace>

View File

@@ -10,6 +10,7 @@ using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Matchers;
using WireMock.Models;
@@ -41,7 +42,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return EmptyArray<AnyOf<string, StringPattern>>.Value;
}
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
public MatchOperator MatchOperator => MatchOperator.Or;
public MatchResult IsMatch(string? input)
{
@@ -50,7 +51,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return MatchScores.Mismatch;
}
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase, WireMockConstants.DefaultRegexTimeout);
try
{
@@ -75,5 +76,11 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return new MatchResult(MatchScores.Mismatch, ex);
}
}
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
throw new NotImplementedException();
}
}
#endif

View File

@@ -6,12 +6,9 @@ using WireMock.Matchers;
namespace WireMock.Authentication;
internal class BasicAuthenticationMatcher : RegexMatcher
internal class BasicAuthenticationMatcher(string username, string password)
: RegexMatcher(BuildPattern(username, password))
{
public BasicAuthenticationMatcher(string username, string password) : base(BuildPattern(username, password))
{
}
public override string Name => nameof(BasicAuthenticationMatcher);
private static string BuildPattern(string username, string password)

View File

@@ -2,6 +2,7 @@
#if NET451 || NET452 || NET46 || NET451 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
using System.Text.RegularExpressions;
using WireMock.Constants;
// ReSharper disable once CheckNamespace
namespace System;
@@ -11,7 +12,7 @@ internal static class StringExtensions
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
{
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
return Regex.Replace(text, oldValue, newValue, options);
return Regex.Replace(text, oldValue, newValue, options, WireMockConstants.DefaultRegexTimeout);
}
}
#endif

View File

@@ -1,15 +1,19 @@
// Copyright © WireMock.Net
using System;
namespace WireMock.Constants;
internal static class WireMockConstants
{
public const int AdminPriority = int.MinValue;
public const int MinPriority = -1_000_000;
public const int ProxyPriority = -2_000_000;
internal static readonly TimeSpan DefaultRegexTimeout = TimeSpan.FromSeconds(10);
internal const int AdminPriority = int.MinValue;
internal const int MinPriority = -1_000_000;
internal const int ProxyPriority = -2_000_000;
public const string ContentTypeJson = "application/json";
public const string ContentTypeTextPlain = "text/plain";
internal const string ContentTypeJson = "application/json";
internal const string ContentTypeTextPlain = "text/plain";
public const string NoMatchingFound = "No matching mapping found";
}
internal const string NoMatchingFound = "No matching mapping found";
}

View File

@@ -22,6 +22,16 @@ public static class AnyOfExtensions
return value.IsFirst ? value.First : value.Second.Pattern;
}
/// <summary>
/// Gets the patterns.
/// </summary>
/// <param name="values">AnyOf types</param>
/// <returns>string values</returns>
public static string[] GetPatterns(this AnyOf<string, StringPattern>[] values)
{
return values.Select(GetPattern).ToArray();
}
/// <summary>
/// Converts a string-patterns to AnyOf patterns.
/// </summary>

View File

@@ -14,12 +14,12 @@ namespace WireMock.Http;
/// </summary>
internal static class HttpKnownHeaderNames
{
// https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
// - https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
// - ContentLength is allowed per #720
private static readonly string[] RestrictedResponseHeaders =
{
Accept,
Connection,
ContentLength,
ContentType,
Date, // RFC1123Pattern
Expect,

View File

@@ -9,6 +9,7 @@ using Newtonsoft.Json;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Http;
@@ -33,12 +34,14 @@ internal static class HttpRequestMessageHelper
MediaTypeHeaderValue.TryParse(value, out contentType);
}
httpRequestMessage.Content = requestMessage.BodyData?.DetectedBodyType switch
var bodyData = requestMessage.BodyData;
httpRequestMessage.Content = bodyData?.GetBodyType() switch
{
BodyType.Bytes => ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType),
BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType),
BodyType.String => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
BodyType.FormUrlEncoded => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
BodyType.Bytes => ByteArrayContentHelper.Create(bodyData!.BodyAsBytes!, contentType),
BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(bodyData!.BodyAsJson), contentType),
BodyType.String => StringContentHelper.Create(bodyData!.BodyAsString!, contentType),
BodyType.FormUrlEncoded => StringContentHelper.Create(bodyData!.BodyAsString!, contentType),
_ => httpRequestMessage.Content
};

View File

@@ -141,7 +141,7 @@ public interface IMapping
/// <summary>
/// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional]
/// </summary>
IdOrText? ProtoDefinition { get; }
IdOrTexts? ProtoDefinition { get; }
/// <summary>
/// ProvideResponseAsync
@@ -175,26 +175,7 @@ public interface IMapping
/// <summary>
/// Define a Grpc ProtoDefinition which is used for this mapping (request and response).
/// </summary>
/// <param name="protoDefinition">The proto definition as text.</param>
/// <param name="protoDefinition">The proto definitions as id or text.</param>
/// <returns>The <see cref="IMapping"/>.</returns>
IMapping WithProtoDefinition(IdOrText protoDefinition);
}
/*
executionConditionState">State in which the current mapping can occur. [Optional]
nextState">The next state which will occur after the current mapping execution. [Optional]
stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]
webhooks">The Webhooks. [Optional]
useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]
timeSettings">The TimeSettings. [Optional]
data">The data object. [Optional]
string? executionConditionState,
string? nextState,
int? stateTimes,
IWebhook[]? webhooks,
bool? useWebhooksFireAndForget,
ITimeSettings? timeSettings,
object? data,
*/
IMapping WithProtoDefinition(IdOrTexts protoDefinition);
}

View File

@@ -52,15 +52,15 @@ public class WireMockConsoleLogger : IWireMockLogger
}
/// <see cref="IWireMockLogger.Error(string, Exception)"/>
public void Error(string formatString, Exception exception)
public void Error(string message, Exception exception)
{
Console.WriteLine(Format("Error", formatString, exception.Message));
Console.WriteLine(Format("Error", $"{message} {{0}}", exception));
if (exception is AggregateException ae)
{
ae.Handle(ex =>
{
Console.WriteLine(Format("Error", "Exception {0}", ex.Message));
Console.WriteLine(Format("Error", "Exception {0}", ex));
return true;
});
}

View File

@@ -36,7 +36,7 @@ public class WireMockNullLogger : IWireMockLogger
}
/// <see cref="IWireMockLogger.Error(string, Exception)"/>
public void Error(string formatString, Exception exception)
public void Error(string message, Exception exception)
{
// Log nothing
}

View File

@@ -82,7 +82,7 @@ public class Mapping : IMapping
public double? Probability { get; private set; }
/// <inheritdoc />
public IdOrText? ProtoDefinition { get; private set; }
public IdOrTexts? ProtoDefinition { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
@@ -189,7 +189,7 @@ public class Mapping : IMapping
}
/// <inheritdoc />
public IMapping WithProtoDefinition(IdOrText protoDefinition)
public IMapping WithProtoDefinition(IdOrTexts protoDefinition)
{
ProtoDefinition = protoDefinition;
return this;

View File

@@ -130,7 +130,10 @@ public class MappingBuilder : IMappingBuilder
private IMapping[] GetNonAdminMappings()
{
return _options.Mappings.Values.Where(m => !m.IsAdminInterface).OrderBy(m => m.UpdatedAt).ToArray();
return _options.Mappings.Values
.Where(m => !m.IsAdminInterface)
.OrderBy(m => m.Guid)
.ToArray();
}
private void RegisterMapping(IMapping mapping, bool saveToFile)

View File

@@ -82,7 +82,7 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
case JTokenType.Object:
var nestedValues = value.ToObject<Dictionary<string, JToken>>();
return nestedValues?.Any() != true ||
nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key) ?? input[pair.Key])); // First try to select based on JPath expression, else just get the value.
case JTokenType.Array:
var valuesArray = value.ToObject<JToken[]>();

View File

@@ -2,7 +2,10 @@
using System.Net.Http.Headers;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -19,7 +22,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this([pattern], ignoreCase)
{
}
@@ -29,7 +32,8 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour,
[pattern], ignoreCase)
{
}
@@ -50,7 +54,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
{
_patterns = patterns;
_patterns = Guard.NotNull(patterns);
}
/// <inheritdoc />
@@ -72,4 +76,15 @@ public class ContentTypeMatcher : WildcardMatcher
/// <inheritdoc />
public override string Name => nameof(ContentTypeMatcher);
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}" +
$")";
}
}

View File

@@ -4,7 +4,9 @@ using System;
using System.Linq;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -86,8 +88,20 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string Name => "ExactMatcher";
public string Name => nameof(ExactMatcher);
/// <inheritdoc />
public bool IgnoreCase { get; }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_values)}" +
$")";
}
}

View File

@@ -72,5 +72,11 @@ public class ExactObjectMatcher : IObjectMatcher
}
/// <inheritdoc />
public string Name => "ExactObjectMatcher";
public string Name => nameof(ExactObjectMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
}

View File

@@ -1,8 +1,10 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.Linq;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
@@ -27,7 +29,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public FormUrlEncodedMatcher(
AnyOf<string, StringPattern> pattern,
bool ignoreCase = false,
@@ -42,7 +44,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public FormUrlEncodedMatcher(
MatchBehaviour matchBehaviour,
AnyOf<string, StringPattern> pattern,
@@ -57,7 +59,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// </summary>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public FormUrlEncodedMatcher(
AnyOf<string, StringPattern>[] patterns,
bool ignoreCase = false,
@@ -72,7 +74,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public FormUrlEncodedMatcher(
MatchBehaviour matchBehaviour,
AnyOf<string, StringPattern>[] patterns,
@@ -112,7 +114,20 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
return new MatchResult(MatchScores.Mismatch);
}
var matches = GetMatches(inputNameValueCollection);
var score = MatchScores.ToScore(matches, MatchOperator);
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
}
private bool[] GetMatches(IDictionary<string, string> inputNameValueCollection)
{
var matches = new List<bool>();
if (_pairs.Count > inputNameValueCollection.Count)
{
matches.AddRange(Enumerable.Repeat(false, _pairs.Count - inputNameValueCollection.Count));
}
foreach (var inputKeyValuePair in inputNameValueCollection)
{
var match = false;
@@ -132,8 +147,7 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
matches.Add(match);
}
var score = MatchScores.ToScore(matches.ToArray(), MatchOperator);
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
return matches.ToArray();
}
/// <inheritdoc />
@@ -150,4 +164,16 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
}

View File

@@ -113,16 +113,16 @@ public class GraphQLMatcher : IStringMatcher
{
try
{
var executionResult = new DocumentExecuter().ExecuteAsync(_ =>
var executionResult = new DocumentExecuter().ExecuteAsync(eo =>
{
_.ThrowOnUnhandledException = true;
eo.ThrowOnUnhandledException = true;
_.Schema = _schema;
_.Query = graphQLRequest.Query;
eo.Schema = _schema;
eo.Query = graphQLRequest.Query;
if (graphQLRequest.Variables != null)
{
_.Variables = new Inputs(graphQLRequest.Variables);
eo.Variables = new Inputs(graphQLRequest.Variables);
}
}).GetAwaiter().GetResult();
@@ -156,6 +156,12 @@ public class GraphQLMatcher : IStringMatcher
/// <inheritdoc />
public string Name => nameof(GraphQLMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private static bool TryGetGraphQLRequest(string input, [NotNullWhen(true)] out GraphQLRequest? graphQLRequest)
{
try

View File

@@ -16,4 +16,10 @@ public interface IMatcher
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Get the C# code arguments.
/// </summary>
/// <returns></returns>
string GetCSharpCodeArguments();
}

View File

@@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -89,7 +90,7 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
Exception? exception = null;
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
if (input != null && input is not byte[])
{
try
{
@@ -116,7 +117,18 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string Name => "JsonPathMatcher";
public string Name => nameof(JsonPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private double IsMatch(JToken jToken)
{

View File

@@ -8,6 +8,7 @@ using Newtonsoft.Json;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -115,4 +116,15 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// <inheritdoc />
public string Name => nameof(JmesPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Util;
using JsonUtils = WireMock.Util.JsonUtils;
@@ -98,6 +99,18 @@ public class JsonMatcher : IJsonMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
}
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
/// <summary>
/// Compares the input against the matcher value
/// </summary>

View File

@@ -1,5 +1,8 @@
// Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Util;
namespace WireMock.Matchers;
/// <summary>
@@ -34,4 +37,16 @@ public class JsonPartialMatcher : AbstractJsonPartialMatcher
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, MatchOperator.Or, value);
return exactStringMatcher.IsMatch(input).IsPerfect();
}
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
}

View File

@@ -1,5 +1,8 @@
// Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Util;
namespace WireMock.Matchers;
/// <summary>
@@ -34,4 +37,16 @@ public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
return wildcardStringMatcher.IsMatch(input).IsPerfect();
}
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
}

View File

@@ -9,6 +9,7 @@ using Stef.Validation;
using WireMock.Extensions;
using WireMock.Json;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -136,4 +137,15 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// <inheritdoc />
public string Name => nameof(LinqMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
}

View File

@@ -3,6 +3,7 @@
#if MIMEKIT
using System;
using MimeKit;
using WireMock.Extensions;
using WireMock.Matchers;
using WireMock.Matchers.Helpers;
using WireMock.Models;
@@ -60,13 +61,13 @@ public class MimePartMatcher : IMatcher
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
ContentMatcher = contentMatcher;
_funcs = new[]
{
_funcs =
[
mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect,
mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect,
mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect,
MatchOnContent
};
];
}
/// <summary>
@@ -94,6 +95,12 @@ public class MimePartMatcher : IMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private MatchResult MatchOnContent(MimePart mimePart)
{
if (ContentMatcher == null)

View File

@@ -3,7 +3,9 @@
using System;
using System.Linq;
using AnyOfTypes;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -70,5 +72,14 @@ public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
public MatchOperator MatchOperator => MatchOperator.Or;
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}" +
$")";
}
}

View File

@@ -2,6 +2,7 @@
#if PROTOBUF
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ProtoBufJsonConverter;
@@ -25,9 +26,9 @@ public class ProtoBufMatcher : IProtoBufMatcher
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// The Func to define The proto definition as text.
/// The Func to define the proto definition as id or texts.
/// </summary>
public Func<IdOrText> ProtoDefinition { get; }
public Func<IdOrTexts> ProtoDefinition { get; }
/// <summary>
/// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".
@@ -44,12 +45,12 @@ public class ProtoBufMatcher : IProtoBufMatcher
/// <summary>
/// Initializes a new instance of the <see cref="ProtoBufMatcher"/> class.
/// </summary>
/// <param name="protoDefinition">The proto definition.</param>
/// <param name="protoDefinition">The proto definition as id or text.</param>
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
/// <param name="matcher">The optional jsonMatcher to use to match the ProtoBuf as (json) object.</param>
public ProtoBufMatcher(
Func<IdOrText> protoDefinition,
Func<IdOrTexts> protoDefinition,
string messageType,
MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch,
IObjectMatcher? matcher = null
@@ -89,6 +90,12 @@ public class ProtoBufMatcher : IProtoBufMatcher
return DecodeAsync(input, false, cancellationToken);
}
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private async Task<object?> DecodeAsync(byte[]? input, bool throwException, CancellationToken cancellationToken)
{
if (input == null)
@@ -96,7 +103,11 @@ public class ProtoBufMatcher : IProtoBufMatcher
return null;
}
var request = new ConvertToObjectRequest(ProtoDefinition().Text, MessageType, input);
var protoDefinitions = ProtoDefinition().Texts;
var resolver = new WireMockProtoFileResolver(protoDefinitions);
var request = new ConvertToObjectRequest(protoDefinitions[0], MessageType, input)
.WithProtoFileResolver(resolver);
try
{

View File

@@ -5,10 +5,12 @@ using System.Linq;
using System.Text.RegularExpressions;
using AnyOfTypes;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.RegularExpressions;
using Stef.Validation;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -21,6 +23,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly Regex[] _expressions;
private readonly bool _useRegexExtended;
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
@@ -37,7 +40,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
bool ignoreCase = false,
bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) :
this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, useRegexExtended, matchOperator)
{
}
@@ -55,7 +58,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
bool ignoreCase = false,
bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) :
this(matchBehaviour, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
this(matchBehaviour, [pattern], ignoreCase, useRegexExtended, matchOperator)
{
}
@@ -76,17 +79,18 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{
_patterns = Guard.NotNull(patterns);
IgnoreCase = ignoreCase;
_useRegexExtended = useRegexExtended;
MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
var options = RegexOptions.Compiled | RegexOptions.Multiline;
if (ignoreCase)
{
options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options)).ToArray();
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options, WireMockConstants.DefaultRegexTimeout)).ToArray();
}
/// <inheritdoc />
@@ -125,4 +129,16 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(_useRegexExtended)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
}

View File

@@ -19,10 +19,10 @@ public class RequestMessageProtoBufMatcher : IRequestMatcher
/// Initializes a new instance of the <see cref="RequestMessageProtoBufMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
/// <param name="protoDefinition">The Func to define The proto definition as text.</param>
/// <param name="protoDefinition">The Func to define the proto definitions as id or text.</param>
/// <param name="messageType">The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}".</param>
/// <param name="matcher">The optional matcher to use to match the ProtoBuf as (json) object.</param>
public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func<IdOrText> protoDefinition, string messageType, IObjectMatcher? matcher = null)
public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func<IdOrTexts> protoDefinition, string messageType, IObjectMatcher? matcher = null)
{
#if PROTOBUF
Matcher = new ProtoBufMatcher(protoDefinition, messageType, matchBehaviour, matcher);

View File

@@ -8,6 +8,7 @@ using SimMetrics.Net.Metric;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -88,6 +89,18 @@ public class SimMetricsMatcher : IStringMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
}
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{_simMetricType.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
private IStringMetric GetStringMetricType()
{
return _simMetricType switch

View File

@@ -6,6 +6,7 @@ using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -70,6 +71,18 @@ public class WildcardMatcher : RegexMatcher
/// <inheritdoc />
public override string Name => nameof(WildcardMatcher);
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
private static AnyOf<string, StringPattern>[] CreateArray(AnyOf<string, StringPattern>[] patterns)
{
return patterns

View File

@@ -10,6 +10,7 @@ using WireMock.Extensions;
using WireMock.Models;
using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Util;
#if !NETSTANDARD1_3
using Wmhelp.XPath2;
#endif
@@ -89,11 +90,6 @@ public class XPathMatcher : IStringMatcher
return CreateMatchResult(score);
}
private MatchResult CreateMatchResult(double score, Exception? exception = null)
{
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
@@ -106,6 +102,23 @@ public class XPathMatcher : IStringMatcher
/// <inheritdoc />
public string Name => nameof(XPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"null, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private MatchResult CreateMatchResult(double score, Exception? exception = null)
{
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
private sealed class XPathEvaluator
{
private XmlDocument? _xmlDocument;
@@ -130,6 +143,7 @@ public class XPathMatcher : IStringMatcher
{
return _xpathNavigator == null ? [] : patterns.Select(pattern => true.Equals(Evaluate(_xpathNavigator, pattern, xmlNamespaceMap))).ToArray();
}
private object Evaluate(XPathNavigator navigator, AnyOf<string, StringPattern> pattern, IEnumerable<XmlNamespace>? xmlNamespaceMap)
{
var xpath = $"boolean({pattern.GetPattern()})";

View File

@@ -52,7 +52,7 @@ public class BodyData : IBodyData
#region ProtoBuf
/// <inheritdoc />
public Func<IdOrText>? ProtoDefinition { get; set; }
public Func<IdOrTexts>? ProtoDefinition { get; set; }
/// <inheritdoc />
public string? ProtoBufMessageType { get; set; }

View File

@@ -75,8 +75,15 @@ namespace WireMock.Owin
private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action<ListenOptions> configure)
{
// Listens on any IP with the given port.
if (urlDetail is { Port: > 0, Host: "0.0.0.0" })
{
kestrelOptions.ListenAnyIP(urlDetail.Port, configure);
return;
}
// Listens on ::1 and 127.0.0.1 with the given port.
if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "0.0.0.0" or "::1" })
if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "::1" })
{
kestrelOptions.ListenLocalhost(urlDetail.Port, configure);
return;
@@ -113,4 +120,4 @@ namespace WireMock.Owin
}
}
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More