Compare commits

..

30 Commits

Author SHA1 Message Date
Stef Heyenrath
13a06b9b38 1.5.5 2022-09-03 08:57:30 +02:00
Stef Heyenrath
74480c8ba9 Add support to use 'mapping' object in in reponse templating (#798)
* mapping

* .

* .
2022-09-03 08:52:05 +02:00
Rafael Moreira Fonseca
862c04e722 Add assertions for request methods (#802)
* Add assertions for request methods

* Fix assertions tests when using connect method

* Remove unnecessary clear and fix assert condition
2022-09-03 08:49:39 +02:00
dependabot[bot]
cd93422554 Bump Microsoft.Owin from 4.1.1 to 4.2.2 in /src/WireMock.Net (#800)
Bumps [Microsoft.Owin](https://github.com/aspnet/AspNetKatana) from 4.1.1 to 4.2.2.
- [Release notes](https://github.com/aspnet/AspNetKatana/releases)
- [Commits](https://github.com/aspnet/AspNetKatana/compare/v4.1.1...v4.2.2)

---
updated-dependencies:
- dependency-name: Microsoft.Owin
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-31 21:19:37 +02:00
Stef Heyenrath
775c4fb2e3 1.5.4 2022-08-24 08:34:20 +02:00
Stef Heyenrath
2d4f513753 Update some NuGet packages (#781) 2022-08-24 08:26:35 +02:00
Stef Heyenrath
3d29d7fb2f Add Response.WithBody with IJsonConverter (#790)
* Response_ProvideResponse_WithBody_IJsonConverter_SystemTextJson

* Guard.NotNull(converter);

* .

* 0.1.0

* j
2022-08-23 15:49:54 +02:00
Florian
f704de65d8 Fixes header match handling using RejectOnMatch behavior (#797)
Co-authored-by: flts <>
2022-08-23 07:52:45 +02:00
Stef Heyenrath
f0d6ed26bc Add check for duplicate Guids when posting multiple mappings in one request (#795)
* Add check for DuplicateGuids

* Add check for duplicate Guids when posting mapping(s)

* mappingModels

* fix ut
2022-08-22 20:05:52 +02:00
Stef Heyenrath
330559b9fd Add support for PEM certificates (#787)
* Support PEM

* net5

* 31

* txt

* FILE

* new

* Fixed

* .

* .

* RSA
2022-08-16 13:26:00 +02:00
Stef Heyenrath
e2bd56531d Add support for Matcher.Pattern in Pact Body mapping (#789)
* Add support for Matcher.Pattern in Pact Body mapping

* SavePact_Get_Request_And_Response_WithNullBody
2022-08-15 09:28:16 +02:00
Stef Heyenrath
d2a1d0f069 Fix WithBody when using Pact and added more nullable annotations (#783)
* More nullable annotations

* .

* .

* FIX

* pact

* .

* p

* xxx

* ...

* auth

* array

* ...
2022-08-11 10:57:33 +02:00
Stef Heyenrath
b1af37f044 Fix Proxying when StartAdminInterface=true (#778)
* ProxyHelper fixes

* .

* more reformat

* .
2022-08-09 19:41:45 +02:00
Stef Heyenrath
be4b0addca 1.5.3 2022-07-29 13:21:22 +02:00
Stef Heyenrath
ae91ed2a79 Update Scriban.Signed to version 5.5.0 (#777) 2022-07-29 13:18:23 +02:00
Stef Heyenrath
968aa598e2 1.5.2 2022-07-24 16:03:30 +02:00
Stef Heyenrath
bdd421e128 JsonPartialMatcher - support Regex (#771)
* JsonPartialMatcher - support Regex

* .

* .

* more tests

* .

* .
2022-07-24 15:54:53 +02:00
Stef Heyenrath
150b448d07 Added some more tests for JsonMatcher + refactored some code to use nullable (#770) 2022-07-09 15:34:17 +02:00
dependabot[bot]
717179fd35 Bump Microsoft.AspNetCore.Server.Kestrel.Core (#769)
Bumps [Microsoft.AspNetCore.Server.Kestrel.Core](https://github.com/aspnet/AspNetCore) from 2.1.3 to 2.1.7.
- [Release notes](https://github.com/aspnet/AspNetCore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/aspnet/AspNetCore/compare/2.1.3...v2.1.7)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Server.Kestrel.Core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-08 21:52:07 +02:00
Stef Heyenrath
9b7e5908cb 1.5.1 2022-07-08 17:41:43 +02:00
Stef Heyenrath
b1032c9dcd Update WireMock.Org.Abstractions and WireMock.Org.RestClient (#765)
* Update WireMock.Org.Abstractions and WireMock.Org.RestClient

* .

* rename
2022-07-08 11:02:18 +02:00
Stef Heyenrath
4d0f96eabe Rename (WireMock.Pact.Models.V2)-Request to PactRequest and -Response to PactResponse (#767) 2022-07-08 10:32:12 +02:00
dependabot[bot]
ef12cb70cc Bump Microsoft.AspNetCore.Http (#766)
Bumps [Microsoft.AspNetCore.Http](https://github.com/aspnet/AspNetCore) from 2.1.1 to 2.1.22.
- [Release notes](https://github.com/aspnet/AspNetCore/releases)
- [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md)
- [Commits](https://github.com/aspnet/AspNetCore/compare/2.1.1...v2.1.22)

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Http
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-08 08:34:19 +02:00
dependabot[bot]
c212d07c53 Bump Newtonsoft.Json in /examples/WireMock.Net.Client.Net472 (#763)
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.1 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.1...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.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>
2022-06-23 11:58:49 +02:00
dependabot[bot]
b9afb126cf Bump Newtonsoft.Json in /examples/WireMock.Net.WebApplication.NETCore2 (#762)
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 11.0.2 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/11.0.2...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.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>
2022-06-23 10:53:43 +02:00
Stef Heyenrath
8dc9c4b46c 1.5.0 2022-06-09 21:35:44 +02:00
Stef Heyenrath
0441c1d85e Add MatchOperator "Or", "And" and "Average" for patterns (#755)
* wip

* ...

* .

* ...

* ...

* path

* url

* b

* t

* client

* .

* RequestMessageMethodMatcherTests

* .

* h

* .

* fix tests

* .
2022-06-09 21:31:54 +02:00
Stef Heyenrath
1f23022460 1.4.43 2022-05-21 16:15:11 +02:00
Stef Heyenrath
8d57f37261 Add WireMock.Net.xUnit project (#759)
* WireMock.Net.xunit

* Xunit

* c

* .

* x
2022-05-21 09:00:24 +02:00
Kenneth Siewers Møller
ca6c39c63a Log correct exception message when handling aggregate exceptions in console logger (#757)
Co-authored-by: Kenneth Siewers Møller <ksm@templafy.com>
2022-05-19 23:20:47 +02:00
312 changed files with 18571 additions and 21499 deletions

View File

@@ -1,3 +1,50 @@
# 1.5.5 (03 September 2022)
- [#798](https://github.com/WireMock-Net/WireMock.Net/pull/798) - Add support to use 'mapping' object in in reponse templating [feature] contributed by [StefH](https://github.com/StefH)
- [#800](https://github.com/WireMock-Net/WireMock.Net/pull/800) - Bump Microsoft.Owin from 4.1.1 to 4.2.2 in /src/WireMock.Net (net46) [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#802](https://github.com/WireMock-Net/WireMock.Net/pull/802) - Add assertions for request methods contributed by [rafaelmfonseca](https://github.com/rafaelmfonseca)
- [#772](https://github.com/WireMock-Net/WireMock.Net/issues/772) - How to get matched mapping by HttpRequest or HttpRequestMessage [feature]
# 1.5.4 (24 August 2022)
- [#778](https://github.com/WireMock-Net/WireMock.Net/pull/778) - Fix Proxying when StartAdminInterface=true [bug] contributed by [StefH](https://github.com/StefH)
- [#781](https://github.com/WireMock-Net/WireMock.Net/pull/781) - Update some NuGet packages [feature] contributed by [StefH](https://github.com/StefH)
- [#783](https://github.com/WireMock-Net/WireMock.Net/pull/783) - Fix WithBody when using Pact and added more nullable annotations [feature] contributed by [StefH](https://github.com/StefH)
- [#787](https://github.com/WireMock-Net/WireMock.Net/pull/787) - Add support for PEM certificates contributed by [StefH](https://github.com/StefH)
- [#789](https://github.com/WireMock-Net/WireMock.Net/pull/789) - Add support for Matcher.Pattern in Pact Body mapping [feature] contributed by [StefH](https://github.com/StefH)
- [#790](https://github.com/WireMock-Net/WireMock.Net/pull/790) - Add Response.WithBody with IJsonConverter [feature] contributed by [StefH](https://github.com/StefH)
- [#795](https://github.com/WireMock-Net/WireMock.Net/pull/795) - Add check for duplicate Guids when posting multiple mappings in one request contributed by [StefH](https://github.com/StefH)
- [#797](https://github.com/WireMock-Net/WireMock.Net/pull/797) - Fix WithHeader when using RejectOnMatch [bug] contributed by [flts](https://github.com/flts)
- [#775](https://github.com/WireMock-Net/WireMock.Net/issues/775) - When &quot;StartAdminInterface&quot; is true then each time is generated new mapping from the proxy [bug]
- [#784](https://github.com/WireMock-Net/WireMock.Net/issues/784) - Response body is missing in generated pact file when IBodyResponseBuilder.WithBody is used [bug]
- [#785](https://github.com/WireMock-Net/WireMock.Net/issues/785) - Support for PEM certificates when using ssl [feature]
- [#788](https://github.com/WireMock-Net/WireMock.Net/issues/788) - Request body is missing in generated pact file for requests that include matching on request body [bug]
- [#796](https://github.com/WireMock-Net/WireMock.Net/issues/796) - RequestMessageHeaderMatcher with MatchBehaviour.RejectOnMatch reverses match results twice [bug]
# 1.5.3 (29 July 2022)
- [#777](https://github.com/WireMock-Net/WireMock.Net/pull/777) - Update Scriban.Signed to version 5.5.0 [feature] contributed by [StefH](https://github.com/StefH)
- [#776](https://github.com/WireMock-Net/WireMock.Net/issues/776) - Update Scriban.Signed to support more functions, e.g math.random [feature]
# 1.5.2 (24 July 2022)
- [#769](https://github.com/WireMock-Net/WireMock.Net/pull/769) - Bump Microsoft.AspNetCore.Server.Kestrel.Core from 2.1.3 to 2.1.7 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#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)
- [#762](https://github.com/WireMock-Net/WireMock.Net/pull/762) - Bump Newtonsoft.Json from 11.0.2 to 13.0.1 in /examples/WireMock.Net.WebApplication.NETCore2 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#763](https://github.com/WireMock-Net/WireMock.Net/pull/763) - Bump Newtonsoft.Json from 6.0.1 to 13.0.1 in /examples/WireMock.Net.Client.Net472 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#765](https://github.com/WireMock-Net/WireMock.Net/pull/765) - Update WireMock.Org.Abstractions and WireMock.Org.RestClient [feature] contributed by [StefH](https://github.com/StefH)
- [#766](https://github.com/WireMock-Net/WireMock.Net/pull/766) - Bump Microsoft.AspNetCore.Http from 2.1.1 to 2.1.22 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#767](https://github.com/WireMock-Net/WireMock.Net/pull/767) - Rename (WireMock.Pact.Models.V2)-Request to PactRequest and -Response to PactResponse [feature] contributed by [StefH](https://github.com/StefH)
- [#764](https://github.com/WireMock-Net/WireMock.Net/issues/764) - Wrong mapping of method GetAdminMappingsAsync from IWireMockOrgApi [bug]
# 1.5.0 (09 June 2022)
- [#755](https://github.com/WireMock-Net/WireMock.Net/pull/755) - Add MatchOperator &quot;Or&quot;, &quot;And&quot; and &quot;Average&quot; for patterns [feature] contributed by [StefH](https://github.com/StefH)
# 1.4.43 (21 May 2022)
- [#757](https://github.com/WireMock-Net/WireMock.Net/pull/757) - Log correct exception message when handling aggregate exceptions contributed by [siewers](https://github.com/siewers)
- [#759](https://github.com/WireMock-Net/WireMock.Net/pull/759) - Add WireMock.Net.xUnit project [feature] contributed by [StefH](https://github.com/StefH)
- [#756](https://github.com/WireMock-Net/WireMock.Net/issues/756) - WireMockConsoleLogger aggregate exception handling bug? [bug]
- [#758](https://github.com/WireMock-Net/WireMock.Net/issues/758) - Add support for logging to an xUnit ITestOutputHelper [feature]
# 1.4.42 (13 May 2022)
- [#748](https://github.com/WireMock-Net/WireMock.Net/pull/748) - Initial support for converting the mappings to a Pact(flow) json file [feature] contributed by [StefH](https://github.com/StefH)
- [#749](https://github.com/WireMock-Net/WireMock.Net/pull/749) - Swagger support [feature] contributed by [StefH](https://github.com/StefH)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.4.42</VersionPrefix>
<VersionPrefix>1.5.5</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
@@ -25,10 +25,6 @@
<!--<None Include="../../PackageReadme.md" Pack="true" PackagePath=""/>-->
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' != 'net45'">
<!--<Nullable>enable</Nullable>-->
</PropertyGroup>
<Choose>
<!-- The environment variable `Prerelease` is set in the azure-pipelines.yml file. -->
<When Condition=" '$(Prerelease)' != '' ">

View File

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.4.42
SET version=1.5.5
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,9 +1,7 @@
# 1.4.42 (13 May 2022)
- #748 Initial support for converting the mappings to a Pact(flow) json file [feature]
- #749 Swagger support [feature]
- #750 [Snyk] Security upgrade Newtonsoft.Json from 11.0.2 to 13.0.1
- #751 Update NuGets packages [feature]
- #741 Integrate with Pact [feature]
- #753 FluentAssertions - assert the server has not received a call [feature]
# 1.5.5 (03 September 2022)
- #798 Add support to use 'mapping' object in in reponse templating [feature]
- #800 Bump Microsoft.Owin from 4.1.1 to 4.2.2 in /src/WireMock.Net (net46) [dependencies]
- #802 Add assertions for request methods
- #772 How to get matched mapping by HttpRequest or HttpRequestMessage [feature]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -37,6 +37,7 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
| &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.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)

View File

@@ -101,6 +101,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Proxy.NETCoreApp", "examples\WireMock.Net.Console.Proxy.NETCoreApp\WireMock.Net.Console.Proxy.NETCoreApp.csproj", "{670C7562-C154-442E-A249-7D26849BCD13}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.xUnit", "src\WireMock.Net.xUnit\WireMock.Net.xUnit.csproj", "{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NET6.WithCertificate", "examples\WireMock.Net.Console.NET6.WithCertificate\WireMock.Net.Console.NET6.WithCertificate.csproj", "{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -239,6 +243,14 @@ Global
{670C7562-C154-442E-A249-7D26849BCD13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{670C7562-C154-442E-A249-7D26849BCD13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{670C7562-C154-442E-A249-7D26849BCD13}.Release|Any CPU.Build.0 = Release|Any CPU
{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}.Release|Any CPU.Build.0 = Release|Any CPU
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -279,6 +291,8 @@ Global
{2215055B-594E-4C2F-99B2-6DF337F02893} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{3F7AA023-6833-4856-A08A-4B5717B592B8} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{670C7562-C154-442E-A249-7D26849BCD13} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

@@ -1,18 +1,22 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AD/@EntryIndexedValue">AD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CS/@EntryIndexedValue">CS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EC/@EntryIndexedValue">EC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSA/@EntryIndexedValue">RSA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TE/@EntryIndexedValue">TE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TSV/@EntryIndexedValue">TSV</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TTL/@EntryIndexedValue">TTL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WWW/@EntryIndexedValue">WWW</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XMS/@EntryIndexedValue">XMS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XUA/@EntryIndexedValue">XUA</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Flurl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=guidb/@EntryIndexedValue">True</s:Boolean>
<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/=Pacticipant/@EntryIndexedValue">True</s:Boolean>
@@ -24,5 +28,8 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Victoor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhook/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhooks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wiremock/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wiremockserver/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xeger/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=xunit/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Brutal.Dev.StrongNameSigner" version="2.7.1" targetFramework="net472" />
<package id="Newtonsoft.Json" version="6.0.1" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="RestEase" version="1.4.10" targetFramework="net472" />
<package id="WireMock.Net.Abstractions" version="1.2.0" targetFramework="net472" />
<package id="WireMock.Net.RestClient" version="1.2.0" targetFramework="net472" />

View File

@@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="RestEase" Version="1.5.6" />
<PackageReference Include="RestEase" Version="1.5.7" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,16 @@
https://www.scottbrady91.com/openssl/creating-elliptical-curve-keys-using-openssl
# find your curve
openssl ecparam -list_curves
# generate a private key for a curve
openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
# generate corresponding public key
openssl ec -in private-key.pem -pubout -out public-key.pem
# optional: create a self-signed certificate
openssl req -new -x509 -key private-key.pem -out cert.pem -days 360
# optional: convert pem to pfx
openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out cert.pfx

View File

@@ -0,0 +1,52 @@
using System.IO;
using WireMock.Logging;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.NET6.WithCertificate;
class Program
{
static void Main(string[] args)
{
var serverEC = WireMockServer.Start(new WireMockServerSettings
{
Urls = new[] { "https://localhost:8433/" },
StartAdminInterface = true,
Logger = new WireMockConsoleLogger(),
CertificateSettings = new WireMockCertificateSettings
{
// https://www.scottbrady91.com/c-sharp/pem-loading-in-dotnet-core-and-dotnet
// https://www.scottbrady91.com/openssl/creating-elliptical-curve-keys-using-openssl
X509CertificateFilePath = "cert.pem",
X509CertificatePassword = @"
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJZTv6ujGrEwxW+ab1+CtZouRd8PK7PsklVMvJwm1uDmoAoGCCqGSM49
AwEHoUQDQgAE39VoI268uDuIeKmRzr9e9jgMSGeuJTvTG7+cSXmeDymrVgIGXQgm
qKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspQ==
-----END EC PRIVATE KEY-----"
}
});
System.Console.WriteLine("WireMockServer listening at {0}", serverEC.Url);
var serverRSA = WireMockServer.Start(new WireMockServerSettings
{
Urls = new[] { "https://localhost:8434/" },
StartAdminInterface = true,
Logger = new WireMockConsoleLogger(),
CertificateSettings = new WireMockCertificateSettings
{
// https://www.scottbrady91.com/c-sharp/pem-loading-in-dotnet-core-and-dotnet
// https://www.scottbrady91.com/openssl/creating-rsa-keys-using-openssl
X509CertificateFilePath = "cert-rsa.pem",
X509CertificatePassword = File.ReadAllText("private-key-rsa.pem")
}
});
System.Console.WriteLine("WireMockServer listening at {0}", serverRSA.Url);
System.Console.WriteLine("Press any key to stop the server(s)");
System.Console.ReadKey();
serverEC.Stop();
serverRSA.Stop();
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="*.pem">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="*.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIErzCCAxegAwIBAgIUeVJ5l3LJPakcwhBGXNfa7UawgPcwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxFTATBgNVBAoM
DFdpcmVNb2NrLk5ldDEVMBMGA1UECwwMV2lyZU1vY2suTmV0MRUwEwYDVQQDDAxX
aXJlTW9jay5OZXQwHhcNMjIwODEyMTQzMjUxWhcNMzIwNjIwMTQzMjUxWjBnMQsw
CQYDVQQGEwJOTDETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UECgwMV2lyZU1v
Y2suTmV0MRUwEwYDVQQLDAxXaXJlTW9jay5OZXQxFTATBgNVBAMMDFdpcmVNb2Nr
Lk5ldDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALyF2sKsueDaZ78r
fQ5IyqWJLYXnYRT94xVfiPoRQNex7JMYwdIt+xEPcfhIlyODxYRxzYTSuXi/cBOM
/svTewIdBmDDyyCDboZ+P8THlzdwCLNHUPONQqJtc0msLVfwPuvDeZIwhIn9CDwC
1EXstWLEePxu1i2/PAfUudYeQunjrP10DE06fyW+ZH7sMSPOSyY4BO4Rt0dk3Cws
U/CEl+bSN5Kx2WkyPxbOvZLa66JmQEaeSZ4ypkhujWE1LuIIQE94P28BzFpHtDWO
1+42K8mqjdnO8eH1/IfAMmOE/o3rKoI4C5aUPyJpDOaz5KFCqdCSBHlb2uo3lqgd
yYOCrVOLIsljp8H4ncfs1AUo+tExNW/5jWYegAZGXLArrWktHEbwa4f+9ZMa7+VS
lKpx6hLI7eMSHBCsQJ7yH8QyLhr0HMjoDw38isGV+mK/N1u47s4oaTQyG+HXH+e/
Shj5OSKnLWBV/eX7YSAJ1hqHgmAbwl/BnuGI3SBXSK4mcjcNvQIDAQABo1MwUTAd
BgNVHQ4EFgQUYhrgWXNdcFpnyz0mifPqYM+kyK4wHwYDVR0jBBgwFoAUYhrgWXNd
cFpnyz0mifPqYM+kyK4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
AYEAmfJZJ019pO7ZXDQ85nEC99+x9+MUnSZ6UuMIiy2VMcS/oea8ugQ4NBYVPpQS
O/xiYENpw36+H4+ctv1tdAbZELGGLBahkkzZedLyiFObxDALu0PP7jQYr4nUjfQj
B/fWuTcCrVmuH3yiutw/sALd1su63VjjZiOCwxMB8LV4T0ojBTHA2D4rqLTiSRgs
sP3CRoWDI2JIr2afM/K8SMczRbo/5ovv0YF9kFcwG9WDEa/oQ67Yu05GFBnItYmT
QP+Br5WiPTLOON9TKm1ZgxLwrhJNHfD2+u9uudkVF5uWyg9ZvB8sYmIw5wSvUFl5
SDj1Pxy4olim54BL5wIwlMMQu+fKp6T89iShgN/NEot3JKW3zDpa/t93IjJXGOlh
O4ECoUzXCtDTnc6aais2SoYjbveP2wduS9MHAQinjTiepzYbhJbySURKqCBu1mN2
EFsU9Pzd1+MA3ZbRfhvl8Jvwdp5GqaFyCqgqmP5oPOcd9ncJowyfobfdqzYMXPGl
bu9i
-----END CERTIFICATE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB9TCCAZugAwIBAgIUYH7UM/DAXzosxsT+ea2jdYvhqqMwCgYIKoZIzj0EAwIw
UDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxFTATBgNVBAoMDFdp
cmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2suTmV0MB4XDTIyMDgxMTE2MjE0
NFoXDTMyMDYxOTE2MjE0NFowUDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUt
U3RhdGUxFTATBgNVBAoMDFdpcmVNb2NrLk5ldDEVMBMGA1UEAwwMV2lyZU1vY2su
TmV0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE39VoI268uDuIeKmRzr9e9jgM
SGeuJTvTG7+cSXmeDymrVgIGXQgmqKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspaNT
MFEwHQYDVR0OBBYEFILL8V+fAtMnccWKGAdkx2Dh/v/TMB8GA1UdIwQYMBaAFILL
8V+fAtMnccWKGAdkx2Dh/v/TMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID
SAAwRQIgKDLAG8OWK6GF5HV4kmWz3kp2V3yVsNK2V9Lw3dSE+YsCIQCK1EEBvuqc
0ncZV4ETVnOY23PWFOMk1VwN2aoTi5n++Q==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEAvIXawqy54Npnvyt9DkjKpYkthedhFP3jFV+I+hFA17HskxjB
0i37EQ9x+EiXI4PFhHHNhNK5eL9wE4z+y9N7Ah0GYMPLIINuhn4/xMeXN3AIs0dQ
841Com1zSawtV/A+68N5kjCEif0IPALURey1YsR4/G7WLb88B9S51h5C6eOs/XQM
TTp/Jb5kfuwxI85LJjgE7hG3R2TcLCxT8ISX5tI3krHZaTI/Fs69ktrromZARp5J
njKmSG6NYTUu4ghAT3g/bwHMWke0NY7X7jYryaqN2c7x4fX8h8AyY4T+jesqgjgL
lpQ/ImkM5rPkoUKp0JIEeVva6jeWqB3Jg4KtU4siyWOnwfidx+zUBSj60TE1b/mN
Zh6ABkZcsCutaS0cRvBrh/71kxrv5VKUqnHqEsjt4xIcEKxAnvIfxDIuGvQcyOgP
DfyKwZX6Yr83W7juzihpNDIb4dcf579KGPk5IqctYFX95fthIAnWGoeCYBvCX8Ge
4YjdIFdIriZyNw29AgMBAAECggGBAJcMsNDWUECG/iVAFP0C+ctUdDMbxr9pBS+0
0i168XdhSeo6JeHfkZCDzY9fqil8hR+vhznrFUxYJtajW+u4UJDK7LdPaUttw3rj
YPir6s8yZuYuOABMqJ04EO1wlQwmpGOGxbuKQEfHg3eB1M8J7/No9H9d1yHkXZbw
rM2QhZCdKZgSCWE/g2ycdizz1hOYUMIYlGqjqzP67iY+hirqMkNxH7Hb6hTNe5ss
ntwxqCcAwnNSlC2661yRp5nBYQUeEfgXAx/cZZ6cILjX6JanDsML/PRY1hOm5hCZ
8/8satOGtd37rgr1cP/kvNMf7uLI8hIeC4JSCymUh6lU6ERpWRoQV8DUE60ztFbi
bQbGU/rseznBN8O1cM6fjduno/n8d4q5wGLjAbIai+xxxTSksbnlvkthRAUfK9/Y
rUdMxqgkDnecCAHof8UPz/Vg3n9J9wl6waFrKa+Kseda1wEB/jf51fb/t0sJP2Dq
n2kcp239zwalUr2XnXfENfeL9IDBiQKBwQDsogaTFy7E5P+66B1ZRDP2X6WgFedH
tjMCVXG4K4VOWp6xMfhieq2d+amMoYi/J3cxS8qDIM64q55caTaB3KTodGrzmvax
avqG58Mpyv9VdEDzMI29D7Xtx5ykoAAWOmQaByH/4J+3IBX6efRDGmSvmoqPoa0V
ChMO0Gw6O9GsH/kVEy2nRaj9dJpOqo05jhh9LLye2stPycCHzYybYqjs0Nt1uboY
3mbiCJBWJ8jZk9KeFhrqCkYB1zZJIJVybJ8CgcEAy/PRm0NZDUx6IJKnwDXBriE0
Qih1ZcvdVi907nhYAlBpAPWisGls6EghBQsfvQ4ZPwHAFBlDu/72JrqGJhkP61mP
D/xT9d59xSU5N90doiInrTHAOoyZEdpul9QvCXxKuFFl3RZnxn0RwPgc23sZUcny
aM4DIWk1541Z84Lxv3tFLXoG5uvqpCkSwEBd9iu0EMHlmoPFkEkY41Q3/zTs46FY
fnWLSdRahKDFHrZTgyu4i/3clbbp9m1cpWLwzUwjAoHAVpSWCT2jPCF5vD5vdpjw
1kV6yU8aV2+/zCvNNxCdbuTTSYw6EHZIjhOqSK1V5nMfNmc/yqi3WnRYtgE9E1jS
8cae11Es0A+PaMrl6qW+tNqbZR+vzKwx6bVuiAGO5pMoyyku9HuQlKVlxUbX67F9
g47tAc6rEJamEHaMEuaOOgdc0Kw6uQhQ46PFTeEzWQq3xR0YSptNZn0wN8AqoTQB
ENz+X128TJsbU7rEbPGTmKBwoKz/3gAySzwePbVxWPOLAoHAAsqehtKAKIdwcHux
YhcaRIjdzz4AhVkp+WEC57Sr97QkC8hQ5rs6q185XHlPgOXtgIhEmcHSxILz2Yna
BjF3n1AFfkGE4Kuf6w/cXaBgJHT1OBCjQenkunLT6q4TyrxxxV4P19vTpcrWcF60
/mgL66uo7rhLIKzw+O9dWNDlACruwnWWHJkECCUrxYfcAV+NwmD1BI1jKdtmRM5F
Se/ughsWO/zd4C/Q4VnV+Nqj//qcNwZNe5saTq4mg3j8NMMjAoHBANRR+WLpgr3f
Kh9vNA+v1gnBUFImheWrJ+Eu75q1sGKrz3gZ8glhewf37YbJVuSKFMEBAg1qobWG
/2B26beXia/NprVuV5vqJNuts29W1/WuDKE7BsNya/quDA1WxTQAzhSA54DYtWXw
UgVTPtEQXL9Wbk2wF98tWiUio4VjV++geVql4qKQUet1IMo1RgRgbQL5hn/rDH0g
ZOX552VdK1xivWQRVA4486eKHlW/lbKJjX0Os6qhNIF57qVquIRQPw==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJZTv6ujGrEwxW+ab1+CtZouRd8PK7PsklVMvJwm1uDmoAoGCCqGSM49
AwEHoUQDQgAE39VoI268uDuIeKmRzr9e9jgMSGeuJTvTG7+cSXmeDymrVgIGXQgm
qKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspQ==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,11 @@
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvIXawqy54Npnvyt9DkjK
pYkthedhFP3jFV+I+hFA17HskxjB0i37EQ9x+EiXI4PFhHHNhNK5eL9wE4z+y9N7
Ah0GYMPLIINuhn4/xMeXN3AIs0dQ841Com1zSawtV/A+68N5kjCEif0IPALURey1
YsR4/G7WLb88B9S51h5C6eOs/XQMTTp/Jb5kfuwxI85LJjgE7hG3R2TcLCxT8ISX
5tI3krHZaTI/Fs69ktrromZARp5JnjKmSG6NYTUu4ghAT3g/bwHMWke0NY7X7jYr
yaqN2c7x4fX8h8AyY4T+jesqgjgLlpQ/ImkM5rPkoUKp0JIEeVva6jeWqB3Jg4Kt
U4siyWOnwfidx+zUBSj60TE1b/mNZh6ABkZcsCutaS0cRvBrh/71kxrv5VKUqnHq
Esjt4xIcEKxAnvIfxDIuGvQcyOgPDfyKwZX6Yr83W7juzihpNDIb4dcf579KGPk5
IqctYFX95fthIAnWGoeCYBvCX8Ge4YjdIFdIriZyNw29AgMBAAE=
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE39VoI268uDuIeKmRzr9e9jgMSGeu
JTvTG7+cSXmeDymrVgIGXQgmqKA8TDXpJNrRhWMd/fpsnWu1JwJUjBmspQ==
-----END PUBLIC KEY-----

View File

@@ -1,22 +1,21 @@
using System.IO;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;
using log4net.Repository;
using WireMock.Net.ConsoleApplication;
namespace WireMock.Net.Console.NETCoreApp
namespace WireMock.Net.Console.NETCoreApp;
static class Program
{
static class Program
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main(params string[] args)
{
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
static void Main(params string[] args)
{
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
MainApp.Run();
}
MainApp.Run();
}
}

View File

@@ -79,7 +79,7 @@ namespace WireMock.Net.ConsoleApplication
// server.AllowPartialMapping();
server.Given(Request.Create().WithPath("/mypath").UsingPost())
server.Given(Request.Create().WithPath(MatchOperator.Or, "/mypath", "/mypath1", "/mypath2").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson("{{JsonPath.SelectToken request.body \"..name\"}}")

View File

@@ -1,15 +1,14 @@
using System.IO;
using System.IO;
using log4net.Config;
namespace WireMock.Net.ConsoleApplication
{
static class Program
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
namespace WireMock.Net.ConsoleApplication;
MainApp.Run();
}
static class Program
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
MainApp.Run();
}
}

View File

@@ -80,7 +80,6 @@
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="libman.json" />
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,73 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that <see langword="null"/> is allowed as an input even if the
/// corresponding type disallows it.
/// </summary>
#endif
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property,
Inherited = false
)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class AllowNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="AllowNullAttribute"/> class.
/// </summary>
#endif
public AllowNullAttribute() { }
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,73 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that <see langword="null"/> is disallowed as an input even if the
/// corresponding type allows it.
/// </summary>
#endif
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property,
Inherited = false
)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class DisallowNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="DisallowNullAttribute"/> class.
/// </summary>
#endif
public DisallowNullAttribute() { }
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,70 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that a method that will never return under any circumstance.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class DoesNotReturnAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="DoesNotReturnAttribute"/> class.
/// </summary>
///
#endif
public DoesNotReturnAttribute() { }
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,88 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that the method will not return if the associated <see cref="Boolean"/>
/// parameter is passed the specified value.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class DoesNotReturnIfAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets the condition parameter value.
/// Code after the method is considered unreachable by diagnostics if the argument
/// to the associated parameter matches this value.
/// </summary>
#endif
public bool ParameterValue { get; }
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="DoesNotReturnIfAttribute"/>
/// class with the specified parameter value.
/// </summary>
/// <param name="parameterValue">
/// The condition parameter value.
/// Code after the method is considered unreachable by diagnostics if the argument
/// to the associated parameter matches this value.
/// </param>
#endif
public DoesNotReturnIfAttribute(bool parameterValue)
{
ParameterValue = parameterValue;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,74 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that an output may be <see langword="null"/> even if the
/// corresponding type disallows it.
/// </summary>
#endif
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.ReturnValue,
Inherited = false
)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class MaybeNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="MaybeNullAttribute"/> class.
/// </summary>
#endif
public MaybeNullAttribute() { }
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,85 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that when a method returns <see cref="ReturnValue"/>,
/// the parameter may be <see langword="null"/> even if the corresponding type disallows it.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class MaybeNullWhenAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets the return value condition.
/// If the method returns this value, the associated parameter may be <see langword="null"/>.
/// </summary>
#endif
public bool ReturnValue { get; }
#if DEBUG
/// <summary>
/// Initializes the attribute with the specified return value condition.
/// </summary>
/// <param name="returnValue">
/// The return value condition.
/// If the method returns this value, the associated parameter may be <see langword="null"/>.
/// </param>
#endif
public MaybeNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,96 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// not-<see langword="null"/> values.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class MemberNotNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets field or property member names.
/// </summary>
#endif
public string[] Members { get; }
#if DEBUG
/// <summary>
/// Initializes the attribute with a field or property member.
/// </summary>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
#endif
public MemberNotNullAttribute(string member)
{
Members = new[] { member };
}
#if DEBUG
/// <summary>
/// Initializes the attribute with the list of field and property members.
/// </summary>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
#endif
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,114 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that the method or property will ensure that the listed field and property members have
/// non-<see langword="null"/> values when returning with the specified return value condition.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class MemberNotNullWhenAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets the return value condition.
/// </summary>
#endif
public bool ReturnValue { get; }
#if DEBUG
/// <summary>
/// Gets field or property member names.
/// </summary>
#endif
public string[] Members { get; }
#if DEBUG
/// <summary>
/// Initializes the attribute with the specified return value condition and a field or property member.
/// </summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value,
/// the associated parameter will not be <see langword="null"/>.
/// </param>
/// <param name="member">
/// The field or property member that is promised to be not-<see langword="null"/>.
/// </param>
#endif
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}
#if DEBUG
/// <summary>
/// Initializes the attribute with the specified return value condition and list
/// of field and property members.
/// </summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value,
/// the associated parameter will not be <see langword="null"/>.
/// </param>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
#endif
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,74 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that an output is not <see langword="null"/> even if the
/// corresponding type allows it.
/// </summary>
#endif
[AttributeUsage(
AttributeTargets.Field | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.ReturnValue,
Inherited = false
)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class NotNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Initializes a new instance of the <see cref="NotNullAttribute"/> class.
/// </summary>
#endif
public NotNullAttribute() { }
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,91 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that the output will be non-<see langword="null"/> if the
/// named parameter is non-<see langword="null"/>.
/// </summary>
#endif
[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue,
AllowMultiple = true,
Inherited = false
)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class NotNullIfNotNullAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets the associated parameter name.
/// The output will be non-<see langword="null"/> if the argument to the
/// parameter specified is non-<see langword="null"/>.
/// </summary>
#endif
public string ParameterName { get; }
#if DEBUG
/// <summary>
/// Initializes the attribute with the associated parameter name.
/// </summary>
/// <param name="parameterName">
/// The associated parameter name.
/// The output will be non-<see langword="null"/> if the argument to the
/// parameter specified is non-<see langword="null"/>.
/// </param>
#endif
public NotNullIfNotNullAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -0,0 +1,85 @@
// <auto-generated>
// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable).
// Please see https://github.com/manuelroemer/Nullable for more information.
//
// IMPORTANT:
// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references.
// Consider migrating to PackageReferences instead:
// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
// Migrating brings the following benefits:
// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project.
// * The added files are immutable and can therefore not be modified by coincidence.
// * Updating/Uninstalling the package will work flawlessly.
// </auto-generated>
#region License
// MIT License
//
// Copyright (c) Manuel Römer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#if !NULLABLE_ATTRIBUTES_DISABLE
#nullable enable
#pragma warning disable
namespace System.Diagnostics.CodeAnalysis
{
using global::System;
#if DEBUG
/// <summary>
/// Specifies that when a method returns <see cref="ReturnValue"/>,
/// the parameter will not be <see langword="null"/> even if the corresponding type allows it.
/// </summary>
#endif
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE
[DebuggerNonUserCode]
#endif
internal sealed class NotNullWhenAttribute : Attribute
{
#if DEBUG
/// <summary>
/// Gets the return value condition.
/// If the method returns this value, the associated parameter will not be <see langword="null"/>.
/// </summary>
#endif
public bool ReturnValue { get; }
#if DEBUG
/// <summary>
/// Initializes the attribute with the specified return value condition.
/// </summary>
/// <param name="returnValue">
/// The return value condition.
/// If the method returns this value, the associated parameter will not be <see langword="null"/>.
/// </param>
#endif
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
}
#pragma warning restore
#nullable restore
#endif // NULLABLE_ATTRIBUTES_DISABLE

View File

@@ -43,7 +43,7 @@
<HintPath>..\..\packages\AnyOf.0.3.0\lib\net45\AnyOf.dll</HintPath>
</Reference>
<Reference Include="Fare, Version=2.2.0.0, Culture=neutral, PublicKeyToken=ea68d375bf33a7c8, processorArchitecture=MSIL">
<HintPath>..\..\packages\Fare.2.2.0\lib\net35\Fare.dll</HintPath>
<HintPath>..\..\packages\Fare.2.2.1\lib\net35\Fare.dll</HintPath>
</Reference>
<Reference Include="Handlebars, Version=2.1.2.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.2\lib\net46\Handlebars.dll</HintPath>
@@ -54,23 +54,23 @@
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Core.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.DynamicLinq, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.3.3\lib\net452\HandlebarsDotNet.Helpers.DynamicLinq.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.DynamicLinq, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.3.5\lib\net452\HandlebarsDotNet.Helpers.DynamicLinq.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Humanizer, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Humanizer.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Humanizer.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Humanizer, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Humanizer.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Humanizer.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Json, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Json.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Json.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Json, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Json.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Json.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Random, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Random.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Random.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Random, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Random.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Random.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Xeger, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Xeger.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Xeger.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Xeger, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Xeger.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Xeger.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.XPath, Version=2.3.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.XPath.2.3.3\lib\net452\HandlebarsDotNet.Helpers.XPath.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.XPath, Version=2.3.5.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.XPath.2.3.5\lib\net452\HandlebarsDotNet.Helpers.XPath.dll</HintPath>
</Reference>
<Reference Include="Humanizer, Version=2.14.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
<HintPath>..\..\packages\Humanizer.Core.2.14.1\lib\netstandard2.0\Humanizer.dll</HintPath>
@@ -246,11 +246,23 @@
<Reference Include="Microsoft.Net.Http.Headers, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Net.Http.Headers.2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll</HintPath>
</Reference>
<Reference Include="Namotion.Reflection, Version=2.0.10.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102, processorArchitecture=MSIL">
<HintPath>..\..\packages\Namotion.Reflection.2.0.10\lib\net45\Namotion.Reflection.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="RandomDataGenerator, Version=1.0.13.0, Culture=neutral, PublicKeyToken=ae5c571d29a3b8d9, processorArchitecture=MSIL">
<HintPath>..\..\packages\RandomDataGenerator.Net.1.0.14\lib\net45\RandomDataGenerator.dll</HintPath>
<Reference Include="NJsonSchema, Version=10.6.10.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102, processorArchitecture=MSIL">
<HintPath>..\..\packages\NJsonSchema.10.6.10\lib\net45\NJsonSchema.dll</HintPath>
</Reference>
<Reference Include="NJsonSchema.Extensions, Version=0.1.0.0, Culture=neutral, PublicKeyToken=e52fadf300daf456, processorArchitecture=MSIL">
<HintPath>..\..\packages\NJsonSchema.Extensions.0.1.0\lib\net45\NJsonSchema.Extensions.dll</HintPath>
</Reference>
<Reference Include="NSwag.Core, Version=13.15.10.0, Culture=neutral, PublicKeyToken=c2d88086e098d109, processorArchitecture=MSIL">
<HintPath>..\..\packages\NSwag.Core.13.15.10\lib\net45\NSwag.Core.dll</HintPath>
</Reference>
<Reference Include="RandomDataGenerator, Version=1.0.15.0, Culture=neutral, PublicKeyToken=ae5c571d29a3b8d9, processorArchitecture=MSIL">
<HintPath>..\..\packages\RandomDataGenerator.Net.1.0.16\lib\net45\RandomDataGenerator.dll</HintPath>
</Reference>
<Reference Include="Scriban.Signed, Version=2.1.4.0, Culture=neutral, PublicKeyToken=5675fb69b15f2433, processorArchitecture=MSIL">
<HintPath>..\..\packages\Scriban.Signed.2.1.4\lib\net45\Scriban.Signed.dll</HintPath>
@@ -289,6 +301,10 @@
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.8\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@@ -300,6 +316,7 @@
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Security.Cryptography.Cng, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Security.Cryptography.Cng.4.5.0\lib\net47\System.Security.Cryptography.Cng.dll</HintPath>
</Reference>
@@ -325,14 +342,14 @@
<Reference Include="TinyMapper, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\TinyMapper.3.0.3\lib\net40\TinyMapper.dll</HintPath>
</Reference>
<Reference Include="WireMock.Net, Version=1.4.41.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Net.1.4.41\lib\net461\WireMock.Net.dll</HintPath>
<Reference Include="WireMock.Net, Version=1.5.3.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Net.1.5.3\lib\net461\WireMock.Net.dll</HintPath>
</Reference>
<Reference Include="WireMock.Net.Abstractions, Version=1.4.41.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Net.Abstractions.1.4.41\lib\net451\WireMock.Net.Abstractions.dll</HintPath>
<Reference Include="WireMock.Net.Abstractions, Version=1.5.3.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Net.Abstractions.1.5.3\lib\net451\WireMock.Net.Abstractions.dll</HintPath>
</Reference>
<Reference Include="WireMock.Org.Abstractions, Version=1.4.41.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Org.Abstractions.1.4.41\lib\net45\WireMock.Org.Abstractions.dll</HintPath>
<Reference Include="WireMock.Org.Abstractions, Version=1.5.3.0, Culture=neutral, PublicKeyToken=c8d65537854e1f03, processorArchitecture=MSIL">
<HintPath>..\..\packages\WireMock.Org.Abstractions.1.5.3\lib\net45\WireMock.Org.Abstractions.dll</HintPath>
</Reference>
<Reference Include="XPath2, Version=1.1.3.0, Culture=neutral, PublicKeyToken=463c6d7fb740c7e5, processorArchitecture=MSIL">
<HintPath>..\..\packages\XPath2.1.1.3\lib\net452\XPath2.dll</HintPath>
@@ -351,6 +368,17 @@
<Compile Include="..\WireMock.Net.Console.Net452.Classic\Program.cs">
<Link>Program.cs</Link>
</Compile>
<Compile Include="Nullable\AllowNullAttribute.cs" />
<Compile Include="Nullable\DisallowNullAttribute.cs" />
<Compile Include="Nullable\DoesNotReturnAttribute.cs" />
<Compile Include="Nullable\DoesNotReturnIfAttribute.cs" />
<Compile Include="Nullable\MaybeNullAttribute.cs" />
<Compile Include="Nullable\MaybeNullWhenAttribute.cs" />
<Compile Include="Nullable\MemberNotNullAttribute.cs" />
<Compile Include="Nullable\MemberNotNullWhenAttribute.cs" />
<Compile Include="Nullable\NotNullAttribute.cs" />
<Compile Include="Nullable\NotNullIfNotNullAttribute.cs" />
<Compile Include="Nullable\NotNullWhenAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AnyOf" version="0.3.0" targetFramework="net472" />
<package id="Fare" version="2.2.0" targetFramework="net472" />
<package id="Fare" version="2.2.1" targetFramework="net472" />
<package id="Handlebars.Net" version="2.1.2" targetFramework="net472" />
<package id="Handlebars.Net.Helpers" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Core" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.DynamicLinq" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Humanizer" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Json" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Random" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Xeger" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.XPath" version="2.3.3" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.DynamicLinq" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Humanizer" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Json" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Random" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Xeger" version="2.3.5" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.XPath" version="2.3.5" targetFramework="net472" />
<package id="Humanizer" version="2.14.1" targetFramework="net472" />
<package id="Humanizer.Core" version="2.14.1" targetFramework="net472" />
<package id="Humanizer.Core.af" version="2.14.1" targetFramework="net472" />
@@ -63,6 +63,7 @@
<package id="Humanizer.Core.zh-Hant" version="2.14.1" targetFramework="net472" />
<package id="JmesPath.Net" version="1.0.125" targetFramework="net472" />
<package id="log4net" version="2.0.14" targetFramework="net472" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.8" targetFramework="net472" />
<package id="Microsoft.AspNetCore" version="2.2.0" targetFramework="net472" />
<package id="Microsoft.AspNetCore.Authentication.Abstractions" version="2.2.0" targetFramework="net472" />
<package id="Microsoft.AspNetCore.Authentication.Core" version="2.2.0" targetFramework="net472" />
@@ -119,8 +120,13 @@
<package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="6.12.2" targetFramework="net472" />
<package id="Microsoft.IdentityModel.Tokens" version="6.12.2" targetFramework="net472" />
<package id="Microsoft.Net.Http.Headers" version="2.2.0" targetFramework="net472" />
<package id="Namotion.Reflection" version="2.0.10" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="RandomDataGenerator.Net" version="1.0.14" targetFramework="net472" />
<package id="NJsonSchema" version="10.6.10" targetFramework="net472" />
<package id="NJsonSchema.Extensions" version="0.1.0" targetFramework="net472" />
<package id="NSwag.Core" version="13.15.10" targetFramework="net472" />
<package id="Nullable" version="1.3.0" targetFramework="net472" developmentDependency="true" />
<package id="RandomDataGenerator.Net" version="1.0.16" targetFramework="net472" />
<package id="Scriban.Signed" version="2.1.4" targetFramework="net472" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net461" />
<package id="Stef.Validation" version="0.1.0" targetFramework="net472" />
@@ -141,9 +147,9 @@
<package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net472" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
<package id="TinyMapper" version="3.0.3" targetFramework="net472" />
<package id="WireMock.Net" version="1.4.41" targetFramework="net472" />
<package id="WireMock.Net.Abstractions" version="1.4.41" targetFramework="net472" />
<package id="WireMock.Org.Abstractions" version="1.4.41" targetFramework="net472" />
<package id="WireMock.Net" version="1.5.3" targetFramework="net472" />
<package id="WireMock.Net.Abstractions" version="1.5.3" targetFramework="net472" />
<package id="WireMock.Org.Abstractions" version="1.5.3" targetFramework="net472" />
<package id="XPath2" version="1.1.3" targetFramework="net472" />
<package id="XPath2.Extensions" version="1.1.3" targetFramework="net472" />
</packages>

View File

@@ -1,27 +1,26 @@
using System;
using System.IO;
using System.Linq;
using log4net.Config;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.StandAlone.Net452
{
public class Program
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
using System;
using System.IO;
using System.Linq;
using log4net.Config;
using WireMock.Server;
using WireMock.Settings;
WireMockServer.Start(settings);
namespace WireMock.Net.StandAlone.Net452;
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}
public class Program
{
static void Main(params string[] args)
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}

View File

@@ -1,23 +1,22 @@
using System;
using System.Linq;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.StandAlone.Net461
{
static class Program
{
static void Main(string[] args)
{
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
using System;
using System.Linq;
using WireMock.Server;
using WireMock.Settings;
WireMockServer.Start(settings);
namespace WireMock.Net.StandAlone.Net461;
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}
static class Program
{
static void Main(string[] args)
{
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
{
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
WireMockServer.Start(settings);
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}

View File

@@ -204,8 +204,8 @@
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
</Reference>
<Reference Include="RestEase, Version=1.5.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\RestEase.1.5.5\lib\net45\RestEase.dll</HintPath>
<Reference Include="RestEase, Version=1.5.7.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\RestEase.1.5.7\lib\net452\RestEase.dll</HintPath>
</Reference>
<Reference Include="SimMetrics.Net, Version=1.0.5.0, Culture=neutral, PublicKeyToken=c58dc06d59f3391b, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.5\lib\net45\SimMetrics.Net.dll</HintPath>

View File

@@ -15,7 +15,7 @@
<package id="Microsoft.AspNetCore.Hosting" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Hosting.Abstractions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http" version="2.1.22" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Abstractions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Extensions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Features" version="2.1.1" targetFramework="net461" />
@@ -24,7 +24,7 @@
<package id="Microsoft.AspNetCore.Routing.Abstractions" version="2.1.1" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.IISIntegration" version="2.1.2" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel" version="2.1.3" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel.Core" version="2.1.3" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel.Core" version="2.1.7" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel.Https" version="2.1.3" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" version="2.1.3" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" version="2.1.3" targetFramework="net461" />
@@ -59,7 +59,7 @@
<package id="MimeKitLite" version="2.0.7" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
<package id="Owin" version="1.0" targetFramework="net461" />
<package id="RestEase" version="1.5.5" targetFramework="net461" />
<package id="RestEase" version="1.5.7" targetFramework="net461" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net461" />
<package id="System.Buffers" version="4.5.0" targetFramework="net461" />
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />

View File

@@ -12,7 +12,7 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0'">
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.9" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">

View File

@@ -1,19 +1,27 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// Body Model
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class BodyModel
{
/// <summary>
/// Body Model
/// Gets or sets the matcher.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class BodyModel
{
/// <summary>
/// Gets or sets the matcher.
/// </summary>
public MatcherModel? Matcher { get; set; }
public MatcherModel? Matcher { get; set; }
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public MatcherModel[]? Matchers { get; set; }
}
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public MatcherModel[]? Matchers { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -1,14 +1,22 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// ClientIPModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class ClientIPModel
{
/// <summary>
/// ClientIPModel
/// Gets or sets the matchers.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class ClientIPModel
{
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public MatcherModel[] Matchers { get; set; }
}
public MatcherModel[]? Matchers { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -1,31 +1,39 @@
using System.Collections.Generic;
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// Header Model
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class HeaderModel
{
/// <summary>
/// Header Model
/// Gets or sets the name.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class HeaderModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; } = null!;
public string Name { get; set; } = null!;
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public IList<MatcherModel>? Matchers { get; set; }
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public IList<MatcherModel>? Matchers { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
}
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -1,78 +1,77 @@
using System;
using WireMock.Models;
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// MappingModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class MappingModel
{
/// <summary>
/// MappingModel
/// Gets or sets the unique identifier.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class MappingModel
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
public Guid? Guid { get; set; }
public Guid? Guid { get; set; }
/// <summary>
/// Gets or sets the TimeSettings when which this mapping should be used.
/// </summary>
public TimeSettingsModel TimeSettings { get; set; }
/// <summary>
/// Gets or sets the TimeSettings when which this mapping should be used.
/// </summary>
public TimeSettingsModel? TimeSettings { get; set; }
/// <summary>
/// The unique title.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The unique title.
/// </summary>
public string? Title { get; set; }
/// <summary>
/// The description.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The description.
/// </summary>
public string? Description { get; set; }
/// <summary>
/// The priority. (A low value means higher priority.)
/// </summary>
public int? Priority { get; set; }
/// <summary>
/// The priority. (A low value means higher priority.)
/// </summary>
public int? Priority { get; set; }
/// <summary>
/// The Scenario.
/// </summary>
public string Scenario { get; set; }
/// <summary>
/// The Scenario.
/// </summary>
public string? Scenario { get; set; }
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
public string WhenStateIs { get; set; }
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
public string? WhenStateIs { get; set; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null state will not be changed.
/// </summary>
public string SetStateTo { get; set; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null state will not be changed.
/// </summary>
public string? SetStateTo { get; set; }
/// <summary>
/// The request model.
/// </summary>
public RequestModel Request { get; set; }
/// <summary>
/// The request model.
/// </summary>
public RequestModel Request { get; set; }
/// <summary>
/// The response model.
/// </summary>
public ResponseModel Response { get; set; }
/// <summary>
/// The response model.
/// </summary>
public ResponseModel Response { get; set; }
/// <summary>
/// Saves this mapping as a static mapping file.
/// </summary>
public bool? SaveToFile { get; set; }
/// <summary>
/// Saves this mapping as a static mapping file.
/// </summary>
public bool? SaveToFile { get; set; }
/// <summary>
/// The Webhook.
/// </summary>
public WebhookModel Webhook { get; set; }
/// <summary>
/// The Webhook.
/// </summary>
public WebhookModel? Webhook { get; set; }
/// <summary>
/// The Webhooks.
/// </summary>
public WebhookModel[] Webhooks { get; set; }
}
/// <summary>
/// The Webhooks.
/// </summary>
public WebhookModel[]? Webhooks { get; set; }
}

View File

@@ -1,39 +1,52 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// MatcherModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class MatcherModel
{
/// <summary>
/// MatcherModel
/// Gets or sets the name.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class MatcherModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; }
public string Name { get; set; } = null!;
/// <summary>
/// Gets or sets the pattern. Can be a string (default) or an object.
/// </summary>
public object? Pattern { get; set; }
/// <summary>
/// Gets or sets the pattern. Can be a string (default) or an object.
/// </summary>
public object? Pattern { get; set; }
/// <summary>
/// Gets or sets the patterns. Can be array of strings (default) or an array of objects.
/// </summary>
public object[]? Patterns { get; set; }
/// <summary>
/// Gets or sets the patterns. Can be array of strings (default) or an array of objects.
/// </summary>
public object[]? Patterns { get; set; }
/// <summary>
/// Gets or sets the pattern as a file.
/// </summary>
public string? PatternAsFile { get; set; }
/// <summary>
/// Gets or sets the pattern as a file.
/// </summary>
public string? PatternAsFile { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
}
/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
/// <summary>
/// The Operator to use when multiple patterns are defined. Optional.
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
/// <summary>
/// Support Regex, only used for JsonPartialMatcher.
/// </summary>
public bool? Regex { get; set; }
}

View File

@@ -1,14 +1,22 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// PathModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class PathModel
{
/// <summary>
/// PathModel
/// Gets or sets the matchers.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class PathModel
{
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public MatcherModel[]? Matchers { get; set; }
}
public MatcherModel[]? Matchers { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -28,6 +28,20 @@ public class RequestModel
/// </summary>
public string[]? Methods { get; set; }
/// <summary>
/// Reject on match for Methods.
/// </summary>
public bool? MethodsRejectOnMatch { get; set; }
/// <summary>
/// The Operator to use when Methods are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one method should match.
/// - "and" = All methods should match.
/// - "average" = The average value from all methods.
/// </summary>
public string? MethodsMatchOperator { get; set; }
/// <summary>
/// Gets or sets the Headers.
/// </summary>

View File

@@ -1,14 +1,22 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// UrlModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class UrlModel
{
/// <summary>
/// UrlModel
/// Gets or sets the matchers.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class UrlModel
{
/// <summary>
/// Gets or sets the matchers.
/// </summary>
public MatcherModel[] Matchers { get; set; }
}
}
public MatcherModel[]? Matchers { get; set; }
/// <summary>
/// The Operator to use when matchers are defined. [Optional]
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
}

View File

@@ -1,24 +1,23 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// WebProxy settings
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebProxyModel
{
/// <summary>
/// WebProxy settings
/// A string instance that contains the address of the proxy server.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebProxyModel
{
/// <summary>
/// A string instance that contains the address of the proxy server.
/// </summary>
public string Address { get; set; }
public string Address { get; set; } = null!;
/// <summary>
/// The user name associated with the credentials.
/// </summary>
public string UserName { get; set; }
/// <summary>
/// The user name associated with the credentials. [optional]
/// </summary>
public string? UserName { get; set; }
/// <summary>
/// The password for the user name associated with the credentials.
/// </summary>
public string Password { get; set; }
}
/// <summary>
/// The password for the user name associated with the credentials. [optional]
/// </summary>
public string? Password { get; set; }
}

View File

@@ -1,52 +1,50 @@
using System.Collections.Generic;
using WireMock.Types;
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// RequestModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebhookRequestModel
{
/// <summary>
/// RequestModel
/// Gets or sets the Url.
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebhookRequestModel
{
/// <summary>
/// Gets or sets the Url.
/// </summary>
public string Url { get; set; }
public string Url { get; set; }
/// <summary>
/// The methods
/// </summary>
public string Method { get; set; }
/// <summary>
/// The method
/// </summary>
public string Method { get; set; }
/// <summary>
/// Gets or sets the headers.
/// </summary>
public IDictionary<string, string> Headers { get; set; }
/// <summary>
/// Gets or sets the headers.
/// </summary>
public IDictionary<string, string>? Headers { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public string? Body { get; set; }
/// <summary>
/// Gets or sets the body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// Gets or sets the body (as JSON object).
/// </summary>
public object? BodyAsJson { get; set; }
/// <summary>
/// Use ResponseMessage Transformer.
/// </summary>
public bool? UseTransformer { get; set; }
/// <summary>
/// Use ResponseMessage Transformer.
/// </summary>
public bool? UseTransformer { get; set; }
/// <summary>
/// Gets the type of the transformer.
/// </summary>
public string TransformerType { get; set; }
/// <summary>
/// Gets the type of the transformer.
/// </summary>
public string? TransformerType { get; set; }
/// <summary>
/// The ReplaceNodeOptions to use when transforming a JSON node.
/// </summary>
public string TransformerReplaceNodeOptions { get; set; }
}
/// <summary>
/// The ReplaceNodeOptions to use when transforming a JSON node.
/// </summary>
public string? TransformerReplaceNodeOptions { get; set; }
}

View File

@@ -30,12 +30,12 @@ public class LogEntryModel
/// <summary>
/// The mapping unique title.
/// </summary>
public string MappingTitle { get; set; }
public string? MappingTitle { get; set; }
/// <summary>
/// The request match result.
/// </summary>
public LogRequestMatchModel RequestMatchResult { get; set; }
public LogRequestMatchModel? RequestMatchResult { get; set; }
/// <summary>
/// The partial mapping unique identifier.
@@ -45,10 +45,10 @@ public class LogEntryModel
/// <summary>
/// The partial mapping unique title.
/// </summary>
public string PartialMappingTitle { get; set; }
public string? PartialMappingTitle { get; set; }
/// <summary>
/// The partial request match result.
/// </summary>
public LogRequestMatchModel PartialRequestMatchResult { get; set; }
public LogRequestMatchModel? PartialRequestMatchResult { get; set; }
}

View File

@@ -3,136 +3,135 @@ using System.Collections.Generic;
using WireMock.Types;
using WireMock.Util;
namespace WireMock
namespace WireMock;
/// <summary>
/// IRequestMessage
/// </summary>
public interface IRequestMessage
{
/// <summary>
/// IRequestMessage
/// Gets the Client IP Address.
/// </summary>
public interface IRequestMessage
{
/// <summary>
/// Gets the Client IP Address.
/// </summary>
string ClientIP { get; }
string ClientIP { get; }
/// <summary>
/// Gets the url (relative).
/// </summary>
string Url { get; }
/// <summary>
/// Gets the url (relative).
/// </summary>
string Url { get; }
/// <summary>
/// Gets the AbsoluteUrl.
/// </summary>
string AbsoluteUrl { get; }
/// <summary>
/// Gets the AbsoluteUrl.
/// </summary>
string AbsoluteUrl { get; }
/// <summary>
/// The ProxyUrl (if a proxy is used).
/// </summary>
string ProxyUrl { get; set; }
/// <summary>
/// The ProxyUrl (if a proxy is used).
/// </summary>
string ProxyUrl { get; set; }
/// <summary>
/// Gets the DateTime.
/// </summary>
DateTime DateTime { get; }
/// <summary>
/// Gets the DateTime.
/// </summary>
DateTime DateTime { get; }
/// <summary>
/// Gets the path (relative).
/// </summary>
string Path { get; }
/// <summary>
/// Gets the path (relative).
/// </summary>
string Path { get; }
/// <summary>
/// Gets the AbsolutePath.
/// </summary>
string AbsolutePath { get; }
/// <summary>
/// Gets the AbsolutePath.
/// </summary>
string AbsolutePath { get; }
/// <summary>
/// Gets the path segments.
/// </summary>
string[] PathSegments { get; }
/// <summary>
/// Gets the path segments.
/// </summary>
string[] PathSegments { get; }
/// <summary>
/// Gets the absolute path segments.
/// </summary>
string[] AbsolutePathSegments { get; }
/// <summary>
/// Gets the absolute path segments.
/// </summary>
string[] AbsolutePathSegments { get; }
/// <summary>
/// Gets the method.
/// </summary>
string Method { get; }
/// <summary>
/// Gets the method.
/// </summary>
string Method { get; }
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>> Headers { get; }
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>>? Headers { get; }
/// <summary>
/// Gets the cookies.
/// </summary>
IDictionary<string, string> Cookies { get; }
/// <summary>
/// Gets the cookies.
/// </summary>
IDictionary<string, string>? Cookies { get; }
/// <summary>
/// Gets the query.
/// </summary>
IDictionary<string, WireMockList<string>> Query { get; }
/// <summary>
/// Gets the query.
/// </summary>
IDictionary<string, WireMockList<string>>? Query { get; }
/// <summary>
/// Gets the raw query.
/// </summary>
string RawQuery { get; }
/// <summary>
/// Gets the raw query.
/// </summary>
string RawQuery { get; }
/// <summary>
/// The body.
/// </summary>
IBodyData? BodyData { get; }
/// <summary>
/// The body.
/// </summary>
IBodyData? BodyData { get; }
/// <summary>
/// The original body as string. Convenience getter for Handlebars.
/// </summary>
string Body { get; }
/// <summary>
/// The original body as string. Convenience getter for Handlebars.
/// </summary>
string Body { get; }
/// <summary>
/// The body (as JSON object). Convenience getter for Handlebars.
/// </summary>
object BodyAsJson { get; }
/// <summary>
/// The body (as JSON object). Convenience getter for Handlebars.
/// </summary>
object BodyAsJson { get; }
/// <summary>
/// The body (as bytearray). Convenience getter for Handlebars.
/// </summary>
byte[] BodyAsBytes { get; }
/// <summary>
/// The body (as bytearray). Convenience getter for Handlebars.
/// </summary>
byte[] BodyAsBytes { get; }
/// <summary>
/// The detected body type. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyType { get; }
/// <summary>
/// The detected body type. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyType { get; }
/// <summary>
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyTypeFromContentType { get; }
/// <summary>
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyTypeFromContentType { get; }
/// <summary>
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
/// </summary>
string DetectedCompression { get; }
/// <summary>
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
/// </summary>
string DetectedCompression { get; }
/// <summary>
/// Gets the Host
/// </summary>
string Host { get; }
/// <summary>
/// Gets the Host
/// </summary>
string Host { get; }
/// <summary>
/// Gets the protocol
/// </summary>
string Protocol { get; }
/// <summary>
/// Gets the protocol
/// </summary>
string Protocol { get; }
/// <summary>
/// Gets the port
/// </summary>
int Port { get; }
/// <summary>
/// Gets the port
/// </summary>
int Port { get; }
/// <summary>
/// Gets the origin
/// </summary>
string Origin { get; }
}
/// <summary>
/// Gets the origin
/// </summary>
string Origin { get; }
}

View File

@@ -3,60 +3,59 @@ using WireMock.ResponseBuilders;
using WireMock.Types;
using WireMock.Util;
namespace WireMock
namespace WireMock;
/// <summary>
/// IResponseMessage
/// </summary>
public interface IResponseMessage
{
/// <summary>
/// IResponseMessage
/// The Body.
/// </summary>
public interface IResponseMessage
{
/// <summary>
/// The Body.
/// </summary>
IBodyData? BodyData { get; }
IBodyData? BodyData { get; }
/// <summary>
/// Gets the body destination (SameAsSource, String or Bytes).
/// </summary>
string BodyDestination { get; }
/// <summary>
/// Gets the body destination (Null, SameAsSource, String or Bytes).
/// </summary>
string? BodyDestination { get; }
/// <summary>
/// Gets or sets the body.
/// </summary>
string BodyOriginal { get; }
/// <summary>
/// Gets or sets the body.
/// </summary>
string? BodyOriginal { get; }
/// <summary>
/// Gets the Fault percentage.
/// </summary>
double? FaultPercentage { get; }
/// <summary>
/// Gets the Fault percentage.
/// </summary>
double? FaultPercentage { get; }
/// <summary>
/// The FaultType.
/// </summary>
FaultType FaultType { get; }
/// <summary>
/// The FaultType.
/// </summary>
FaultType FaultType { get; }
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>> Headers { get; }
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>>? Headers { get; }
/// <summary>
/// Gets or sets the status code.
/// </summary>
object StatusCode { get; }
/// <summary>
/// Gets or sets the status code.
/// </summary>
object? StatusCode { get; }
/// <summary>
/// Adds the header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="value">The value.</param>
void AddHeader(string name, string value);
/// <summary>
/// Adds the header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="value">The value.</param>
void AddHeader(string name, string value);
/// <summary>
/// Adds the header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="values">The values.</param>
void AddHeader(string name, params string[] values);
}
/// <summary>
/// Adds the header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="values">The values.</param>
void AddHeader(string name, params string[] values);
}

View File

@@ -1,56 +1,55 @@
using System;
using System;
using WireMock.Matchers.Request;
namespace WireMock.Logging
namespace WireMock.Logging;
/// <summary>
/// ILogEntry
/// </summary>
public interface ILogEntry
{
/// <summary>
/// ILogEntry
/// Gets the unique identifier.
/// </summary>
public interface ILogEntry
{
/// <summary>
/// Gets the unique identifier.
/// </summary>
Guid Guid { get; }
Guid Guid { get; }
/// <summary>
/// Gets the mapping unique identifier.
/// </summary>
Guid? MappingGuid { get; }
/// <summary>
/// Gets the mapping unique identifier.
/// </summary>
Guid? MappingGuid { get; }
/// <summary>
/// Gets the mapping unique title.
/// </summary>
string MappingTitle { get; }
/// <summary>
/// Gets the mapping unique title.
/// </summary>
string? MappingTitle { get; }
/// <summary>
/// Gets the partial mapping unique identifier.
/// </summary>
Guid? PartialMappingGuid { get; }
/// <summary>
/// Gets the partial mapping unique identifier.
/// </summary>
Guid? PartialMappingGuid { get; }
/// <summary>
/// Gets the partial mapping unique title.
/// </summary>
string PartialMappingTitle { get; }
/// <summary>
/// Gets the partial mapping unique title.
/// </summary>
string? PartialMappingTitle { get; }
/// <summary>
/// Gets the partial match result.
/// </summary>
IRequestMatchResult PartialMatchResult { get; }
/// <summary>
/// Gets the partial match result.
/// </summary>
IRequestMatchResult PartialMatchResult { get; }
/// <summary>
/// Gets the request match result.
/// </summary>
IRequestMatchResult RequestMatchResult { get; }
/// <summary>
/// Gets the request match result.
/// </summary>
IRequestMatchResult RequestMatchResult { get; }
/// <summary>
/// Gets the request message.
/// </summary>
IRequestMessage RequestMessage { get; }
/// <summary>
/// Gets the request message.
/// </summary>
IRequestMessage RequestMessage { get; }
/// <summary>
/// Gets the response message.
/// </summary>
IResponseMessage ResponseMessage { get; }
}
/// <summary>
/// Gets the response message.
/// </summary>
IResponseMessage ResponseMessage { get; }
}

View File

@@ -1,20 +1,17 @@
using JetBrains.Annotations;
namespace WireMock.Matchers.Request;
namespace WireMock.Matchers.Request
/// <summary>
/// The RequestMatcher interface.
/// </summary>
public interface IRequestMatcher
{
/// <summary>
/// The RequestMatcher interface.
/// Determines whether the specified RequestMessage is match.
/// </summary>
public interface IRequestMatcher
{
/// <summary>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
double GetMatchingScore([NotNull] IRequestMessage requestMessage, [NotNull] IRequestMatchResult requestMatchResult);
}
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult);
}

View File

@@ -1,25 +1,24 @@
using System;
namespace WireMock.Models
namespace WireMock.Models;
/// <summary>
/// TimeSettings: Start, End and TTL
/// </summary>
public interface ITimeSettings
{
/// <summary>
/// TimeSettings: Start, End and TTL
/// Gets or sets the DateTime from which this mapping should be used. In case this is not defined, it's used (default behavior).
/// </summary>
public interface ITimeSettings
{
/// <summary>
/// Gets or sets the DateTime from which this mapping should be used. In case this is not defined, it's used (default behavior).
/// </summary>
DateTime? Start { get; set; }
DateTime? Start { get; set; }
/// <summary>
/// Gets or sets the DateTime from until this mapping should be used. In case this is not defined, it's used forever (default behavior).
/// </summary>
DateTime? End { get; set; }
/// <summary>
/// Gets or sets the DateTime from until this mapping should be used. In case this is not defined, it's used forever (default behavior).
/// </summary>
DateTime? End { get; set; }
/// <summary>
/// Gets or sets the TTL (Time To Live) in seconds for this mapping. In case this is not defined, it's used (default behavior).
/// </summary>
int? TTL { get; set; }
}
/// <summary>
/// Gets or sets the TTL (Time To Live) in seconds for this mapping. In case this is not defined, it's used (default behavior).
/// </summary>
int? TTL { get; set; }
}

View File

@@ -1,13 +1,12 @@
namespace WireMock.Models
namespace WireMock.Models;
/// <summary>
/// IWebhook
/// </summary>
public interface IWebhook
{
/// <summary>
/// IWebhook
/// Request
/// </summary>
public interface IWebhook
{
/// <summary>
/// Request
/// </summary>
IWebhookRequest Request { get; set; }
}
IWebhookRequest Request { get; set; }
}

View File

@@ -22,12 +22,12 @@ namespace WireMock.Models
/// <summary>
/// The Headers to send.
/// </summary>
IDictionary<string, WireMockList<string>> Headers { get; }
IDictionary<string, WireMockList<string>>? Headers { get; }
/// <summary>
/// The body to send.
/// </summary>
IBodyData BodyData { get; set; }
IBodyData? BodyData { get; set; }
/// <summary>
/// Use Transformer.

View File

@@ -35,7 +35,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<!-- See also https://mstack.nl/blog/20210801-source-generators -->
<PackageReference Include="FluentBuilder" Version="0.4.4">
<PackageReference Include="FluentBuilder" Version="0.5.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -29,7 +29,7 @@ public class WireMockAssertions
"Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but no calls were made.",
absoluteUrl)
.Then
.ForCondition(x => _callsCount == null && x.Any(y => y.AbsoluteUrl == absoluteUrl) || _callsCount == x.Count(y => y.AbsoluteUrl == absoluteUrl))
.ForCondition(x => (_callsCount == null && x.Any(y => y.AbsoluteUrl == absoluteUrl)) || (_callsCount == x.Count(y => y.AbsoluteUrl == absoluteUrl)))
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but didn't find it among the calls to {1}.",
_ => absoluteUrl, requests => requests.Select(request => request.AbsoluteUrl));
@@ -48,7 +48,7 @@ public class WireMockAssertions
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but no calls were made.",
url)
.Then
.ForCondition(x => _callsCount == null && x.Any(y => y.Url == url) || _callsCount == x.Count(y => y.Url == url))
.ForCondition(x => (_callsCount == null && x.Any(y => y.Url == url)) || (_callsCount == x.Count(y => y.Url == url)))
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but didn't find it among the calls to {1}.",
_ => url, requests => requests.Select(request => request.Url));
@@ -67,7 +67,7 @@ public class WireMockAssertions
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but no calls were made.",
proxyUrl)
.Then
.ForCondition(x => _callsCount == null && x.Any(y => y.ProxyUrl == proxyUrl) || _callsCount == x.Count(y => y.ProxyUrl == proxyUrl))
.ForCondition(x => (_callsCount == null && x.Any(y => y.ProxyUrl == proxyUrl)) || (_callsCount == x.Count(y => y.ProxyUrl == proxyUrl)))
.FailWith(
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but didn't find it among the calls with {1}.",
_ => proxyUrl, requests => requests.Select(request => request.ProxyUrl));
@@ -86,7 +86,7 @@ public class WireMockAssertions
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but no calls were made.",
clientIP)
.Then
.ForCondition(x => _callsCount == null && x.Any(y => y.ClientIP == clientIP) || _callsCount == x.Count(y => y.ClientIP == clientIP))
.ForCondition(x => (_callsCount == null && x.Any(y => y.ClientIP == clientIP)) || (_callsCount == x.Count(y => y.ClientIP == clientIP)))
.FailWith(
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but didn't find it among the calls from IP(s) {1}.",
_ => clientIP, requests => requests.Select(request => request.ClientIP));
@@ -129,4 +129,59 @@ public class WireMockAssertions
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingConnect(string because = "", params object[] becauseArgs)
=> UsingMethod("CONNECT", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingDelete(string because = "", params object[] becauseArgs)
=> UsingMethod("DELETE", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingGet(string because = "", params object[] becauseArgs)
=> UsingMethod("GET", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingHead(string because = "", params object[] becauseArgs)
=> UsingMethod("HEAD", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingOptions(string because = "", params object[] becauseArgs)
=> UsingMethod("OPTIONS", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPost(string because = "", params object[] becauseArgs)
=> UsingMethod("POST", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPatch(string because = "", params object[] becauseArgs)
=> UsingMethod("PATCH", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPut(string because = "", params object[] becauseArgs)
=> UsingMethod("PUT", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingTrace(string because = "", params object[] becauseArgs)
=> UsingMethod("TRACE", because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingMethod(string method, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList())
.ForCondition(requests => requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but no calls were made.",
method)
.Then
.ForCondition(x => (_callsCount == null && x.Any(y => y.Method == method)) || (_callsCount == x.Count(y => y.Method == method)))
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but didn't find it among the methods {1}.",
_ => method, requests => requests.Select(request => request.Method));
return new AndConstraint<WireMockAssertions>(this);
}
}

View File

@@ -3,138 +3,137 @@ using System.Linq;
using System.Reflection;
using System.Text;
using AnyOfTypes;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Exceptions;
using WireMock.Extensions;
using WireMock.Models;
using Stef.Validation;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="ICSharpCodeMatcher"/>
internal class CSharpCodeMatcher : ICSharpCodeMatcher
{
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="ICSharpCodeMatcher"/>
internal class CSharpCodeMatcher : ICSharpCodeMatcher
private const string TemplateForIsMatchWithString = "public class CodeHelper {{ public bool IsMatch(string it) {{ {0} }} }}";
private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
private readonly string[] _usings =
{
private const string TemplateForIsMatchWithString = "public class CodeHelper {{ public bool IsMatch(string it) {{ {0} }} }}";
"System",
"System.Linq",
"System.Collections.Generic",
"Microsoft.CSharp",
"Newtonsoft.Json.Linq"
};
private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
public MatchBehaviour MatchBehaviour { get; }
private readonly string[] _usings =
{
"System",
"System.Linq",
"System.Collections.Generic",
"Microsoft.CSharp",
"Newtonsoft.Json.Linq"
};
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary>
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public CSharpCodeMatcher([NotNull] params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary>
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public CSharpCodeMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param>
public CSharpCodeMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns)
{
_patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
ThrowException = false;
MatchOperator = matchOperator;
}
public double IsMatch(string? input)
{
return IsMatchInternal(input);
}
public double IsMatch(object? input)
{
return IsMatchInternal(input);
}
public double IsMatchInternal(object? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())).ToArray(), MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="CSharpCodeMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
public CSharpCodeMatcher(MatchBehaviour matchBehaviour, [NotNull] params AnyOf<string, StringPattern>[] patterns)
{
Guard.NotNull(patterns, nameof(patterns));
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
MatchBehaviour = matchBehaviour;
ThrowException = false;
_patterns = patterns;
}
private bool IsMatch(dynamic input, string pattern)
{
bool isMatchWithString = input is string;
var inputValue = isMatchWithString ? input : JObject.FromObject(input);
string source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
public double IsMatch(string input)
{
return IsMatchInternal(input);
}
public double IsMatch(object input)
{
return IsMatchInternal(input);
}
public double IsMatchInternal(object input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())));
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
private bool IsMatch(dynamic input, string pattern)
{
bool isMatchWithString = input is string;
var inputValue = isMatchWithString ? input : JObject.FromObject(input);
string source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
object result = null;
object? result;
#if (NET451 || NET452)
var compilerParams = new System.CodeDom.Compiler.CompilerParameters
var compilerParams = new System.CodeDom.Compiler.CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
ReferencedAssemblies =
{
GenerateInMemory = true,
GenerateExecutable = false,
ReferencedAssemblies =
{
"System.dll",
"System.Core.dll",
"Microsoft.CSharp.dll",
"Newtonsoft.Json.dll"
}
};
using (var codeProvider = new Microsoft.CSharp.CSharpCodeProvider())
{
var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParams, source);
if (compilerResults.Errors.Count != 0)
{
var errors = from System.CodeDom.Compiler.CompilerError er in compilerResults.Errors select er.ToString();
throw new WireMockException(string.Join(", ", errors));
}
object helper = compilerResults.CompiledAssembly.CreateInstance("CodeHelper");
if (helper == null)
{
throw new WireMockException("CSharpCodeMatcher: Unable to create instance from WireMock.CodeHelper");
}
var methodInfo = helper.GetType().GetMethod("IsMatch");
if (methodInfo == null)
{
throw new WireMockException("CSharpCodeMatcher: Unable to find method 'IsMatch' in WireMock.CodeHelper");
}
try
{
result = methodInfo.Invoke(helper, new[] { inputValue });
}
catch (Exception ex)
{
throw new WireMockException("CSharpCodeMatcher: Unable to call method 'IsMatch' in WireMock.CodeHelper", ex);
}
"System.dll",
"System.Core.dll",
"Microsoft.CSharp.dll",
"Newtonsoft.Json.dll"
}
};
using (var codeProvider = new Microsoft.CSharp.CSharpCodeProvider())
{
var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParams, source);
if (compilerResults.Errors.Count != 0)
{
var errors = from System.CodeDom.Compiler.CompilerError er in compilerResults.Errors select er.ToString();
throw new WireMockException(string.Join(", ", errors));
}
var helper = compilerResults.CompiledAssembly?.CreateInstance("CodeHelper");
if (helper == null)
{
throw new WireMockException("CSharpCodeMatcher: Unable to create instance from WireMock.CodeHelper");
}
var methodInfo = helper.GetType().GetMethod("IsMatch");
if (methodInfo == null)
{
throw new WireMockException("CSharpCodeMatcher: Unable to find method 'IsMatch' in WireMock.CodeHelper");
}
try
{
result = methodInfo.Invoke(helper, new[] { inputValue });
}
catch (Exception ex)
{
throw new WireMockException("CSharpCodeMatcher: Unable to call method 'IsMatch' in WireMock.CodeHelper", ex);
}
}
#elif (NET46 || NET461)
dynamic script;
try
@@ -169,11 +168,7 @@ namespace WireMock.Matchers
dynamic script;
try
{
//#if NETSTANDARD2_0
// script = csscript.GenericExtensions.CreateObject(assembly, "*");
//#else
script = CSScripting.ReflectionExtensions.CreateObject(assembly, "*");
//#endif
}
catch (Exception ex)
{
@@ -191,38 +186,40 @@ namespace WireMock.Matchers
#else
throw new NotSupportedException("The 'CSharpCodeMatcher' cannot be used in netstandard 1.3");
#endif
try
{
return (bool)result;
}
catch
{
throw new WireMockException($"Unable to cast result '{result}' to bool");
}
}
private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
try
{
string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
var stringBuilder = new StringBuilder();
foreach (string @using in _usings)
{
stringBuilder.AppendLine($"using {@using};");
}
stringBuilder.AppendLine();
stringBuilder.AppendFormat(template, pattern);
return stringBuilder.ToString();
return (bool)result;
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
catch
{
return _patterns;
throw new WireMockException($"Unable to cast result '{result}' to bool");
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "CSharpCodeMatcher";
}
private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
{
string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
var stringBuilder = new StringBuilder();
foreach (string @using in _usings)
{
stringBuilder.AppendLine($"using {@using};");
}
stringBuilder.AppendLine();
stringBuilder.AppendFormat(template, pattern);
return stringBuilder.ToString();
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "CSharpCodeMatcher";
}

View File

@@ -25,7 +25,7 @@
<PackageReference Include="RamlToOpenApiConverter" Version="0.6.1" />
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.15" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.16" />
<PackageReference Include="Stef.Validation" Version="0.1.0" />
</ItemGroup>

View File

@@ -31,7 +31,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="RestEase" Version="1.5.6" />
<PackageReference Include="RestEase" Version="1.5.7" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,79 @@
using System;
using Newtonsoft.Json;
using Stef.Validation;
using WireMock.Admin.Requests;
using WireMock.Logging;
using Xunit.Abstractions;
namespace WireMock.Net.Xunit;
/// <summary>
/// When using xUnit, this class enables to log the output from WireMock.Net to the <see cref="ITestOutputHelper"/>.
/// </summary>
public sealed class TestOutputHelperWireMockLogger : IWireMockLogger
{
private readonly ITestOutputHelper _testOutputHelper;
/// <summary>
/// Create a new instance on the <see cref="TestOutputHelperWireMockLogger"/>.
/// </summary>
/// <param name="testOutputHelper">Represents a class which can be used to provide test output.</param>
public TestOutputHelperWireMockLogger(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = Guard.NotNull(testOutputHelper);
}
/// <inheritdoc />
public void Debug(string formatString, params object[] args)
{
_testOutputHelper.WriteLine(Format("Debug", formatString, args));
}
/// <inheritdoc />
public void Info(string formatString, params object[] args)
{
_testOutputHelper.WriteLine(Format("Info", formatString, args));
}
/// <inheritdoc />
public void Warn(string formatString, params object[] args)
{
_testOutputHelper.WriteLine(Format("Warning", formatString, args));
}
/// <inheritdoc />
public void Error(string formatString, params object[] args)
{
_testOutputHelper.WriteLine(Format("Error", formatString, args));
}
/// <inheritdoc />
public void Error(string formatString, Exception exception)
{
_testOutputHelper.WriteLine(Format("Error", formatString, exception.Message));
if (exception is AggregateException ae)
{
ae.Handle(ex =>
{
_testOutputHelper.WriteLine(Format("Error", "Exception {0}", ex.Message));
return true;
});
}
}
/// <inheritdoc />
public void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest)
{
var message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
_testOutputHelper.WriteLine(Format("DebugRequestResponse", "Admin[{0}] {1}", isAdminRequest, message));
}
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

@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<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>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.xUnit</AssemblyName>
<RootNamespace>WireMock.Net.Xunit</RootNamespace>
<PackageId>WireMock.Net.xUnit</PackageId>
<PackageTags>tdd;wiremock;test;unittest;xunit</PackageTags>
<ProjectGuid>{0DE0954F-8C00-4E8D-B94A-4361FC1CBE44}</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="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Stef.Validation" Version="0.1.0" />
<PackageReference Include="xUnit.abstractions" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,5 @@
#if !NETSTANDARD1_3
using System;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Text.RegularExpressions;
@@ -6,65 +7,72 @@ using AnyOfTypes;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Stef.Validation;
using WireMock.Matchers;
using WireMock.Models;
namespace WireMock.Authentication
namespace WireMock.Authentication;
/// <summary>
/// https://www.c-sharpcorner.com/article/how-to-validate-azure-ad-token-using-console-application/
/// https://stackoverflow.com/questions/38684865/validation-of-an-azure-ad-bearer-token-in-a-console-application
/// </summary>
internal class AzureADAuthenticationMatcher : IStringMatcher
{
/// <summary>
/// https://www.c-sharpcorner.com/article/how-to-validate-azure-ad-token-using-console-application/
/// https://stackoverflow.com/questions/38684865/validation-of-an-azure-ad-bearer-token-in-a-console-application
/// </summary>
internal class AzureADAuthenticationMatcher : IStringMatcher
private const string BearerPrefix = "Bearer ";
private readonly string _audience;
private readonly string _stsDiscoveryEndpoint;
public AzureADAuthenticationMatcher(string tenant, string audience)
{
private const string BearerPrefix = "Bearer ";
_audience = Guard.NotNullOrEmpty(audience);
_stsDiscoveryEndpoint = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", Guard.NotNullOrEmpty(tenant));
}
private readonly string _audience;
private readonly string _stsDiscoveryEndpoint;
public string Name => nameof(AzureADAuthenticationMatcher);
public AzureADAuthenticationMatcher(string tenant, string audience)
public MatchBehaviour MatchBehaviour => MatchBehaviour.AcceptOnMatch;
public bool ThrowException => false;
public AnyOf<string, StringPattern>[] GetPatterns()
{
return EmptyArray<AnyOf<string, StringPattern>>.Value;
}
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
public double IsMatch(string? input)
{
if (string.IsNullOrEmpty(input))
{
_audience = audience;
_stsDiscoveryEndpoint = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", tenant);
return MatchScores.Mismatch;
}
public string Name => nameof(AzureADAuthenticationMatcher);
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
public MatchBehaviour MatchBehaviour => MatchBehaviour.AcceptOnMatch;
public bool ThrowException => false;
public AnyOf<string, StringPattern>[] GetPatterns()
try
{
return new AnyOf<string, StringPattern>[0];
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(_stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
var config = configManager.GetConfigurationAsync().ConfigureAwait(false).GetAwaiter().GetResult();
var validationParameters = new TokenValidationParameters
{
ValidAudience = _audience,
ValidIssuer = config.Issuer,
IssuerSigningKeys = config.SigningKeys,
ValidateLifetime = true
};
// Throws an Exception as the token is invalid (expired, invalid-formatted, etc.)
new JwtSecurityTokenHandler().ValidateToken(token, validationParameters, out var _);
return MatchScores.Perfect;
}
public double IsMatch(string input)
catch
{
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
try
{
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(_stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
var config = configManager.GetConfigurationAsync().ConfigureAwait(false).GetAwaiter().GetResult();
var validationParameters = new TokenValidationParameters
{
ValidAudience = _audience,
ValidIssuer = config.Issuer,
IssuerSigningKeys = config.SigningKeys,
ValidateLifetime = true
};
// Throws an Exception as the token is invalid (expired, invalid-formatted, etc.)
new JwtSecurityTokenHandler().ValidateToken(token, validationParameters, out var _);
return MatchScores.Perfect;
}
catch
{
return MatchScores.Mismatch;
}
return MatchScores.Mismatch;
}
}
}

View File

@@ -2,19 +2,18 @@ using System;
using System.Text;
using WireMock.Matchers;
namespace WireMock.Authentication
namespace WireMock.Authentication;
internal class BasicAuthenticationMatcher : RegexMatcher
{
internal class BasicAuthenticationMatcher : RegexMatcher
public BasicAuthenticationMatcher(string username, string password) : base(BuildPattern(username, password))
{
public BasicAuthenticationMatcher(string username, string password) : base(BuildPattern(username, password))
{
}
}
public override string Name => nameof(BasicAuthenticationMatcher);
public override string Name => nameof(BasicAuthenticationMatcher);
private static string BuildPattern(string username, string password)
{
return "^(?i)BASIC " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password)) + "$";
}
private static string BuildPattern(string username, string password)
{
return "^(?i)BASIC " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password)) + "$";
}
}

View File

@@ -0,0 +1,11 @@
// ReSharper disable once CheckNamespace
namespace System;
internal static class EmptyArray<T>
{
#if NET451 || NET452
public static readonly T[] Value = new T[0];
#else
public static readonly T[] Value = Array.Empty<T>();
#endif
}

View File

@@ -1,28 +1,26 @@
#if NETSTANDARD1_3
using System;
using System.Net;
#if NETSTANDARD1_3
namespace System.Net
// ReSharper disable once CheckNamespace
namespace System.Net;
internal class WebProxy : IWebProxy
{
internal class WebProxy : IWebProxy
private readonly string _proxy;
public ICredentials? Credentials { get; set; }
public WebProxy(string proxy)
{
private readonly string _proxy;
public ICredentials Credentials { get; set; }
_proxy = proxy;
}
public WebProxy(string proxy)
{
_proxy = proxy;
}
public Uri GetProxy(Uri destination)
{
return new Uri(_proxy);
}
public Uri GetProxy(Uri destination)
{
return new Uri(_proxy);
}
public bool IsBypassed(Uri host)
{
return true;
}
public bool IsBypassed(Uri host)
{
return true;
}
}
#endif

View File

@@ -1,26 +1,24 @@
using System.Collections.Generic;
using System.Linq;
using AnyOfTypes;
using JetBrains.Annotations;
using WireMock.Models;
namespace WireMock.Extensions
namespace WireMock.Extensions;
internal static class AnyOfExtensions
{
internal static class AnyOfExtensions
public static string GetPattern(this AnyOf<string, StringPattern> value)
{
public static string GetPattern([NotNull] this AnyOf<string, StringPattern> value)
{
return value.IsFirst ? value.First : value.Second.Pattern;
}
return value.IsFirst ? value.First : value.Second.Pattern;
}
public static AnyOf<string, StringPattern>[] ToAnyOfPatterns([NotNull] this IEnumerable<string> patterns)
{
return patterns.Select(p => p.ToAnyOfPattern()).ToArray();
}
public static AnyOf<string, StringPattern>[] ToAnyOfPatterns(this IEnumerable<string> patterns)
{
return patterns.Select(p => p.ToAnyOfPattern()).ToArray();
}
public static AnyOf<string, StringPattern> ToAnyOfPattern([CanBeNull] this string pattern)
{
return new AnyOf<string, StringPattern>(pattern);
}
public static AnyOf<string, StringPattern> ToAnyOfPattern(this string pattern)
{
return new AnyOf<string, StringPattern>(pattern);
}
}

View File

@@ -1,35 +1,34 @@
using System;
using JetBrains.Annotations;
using WireMock.Models;
namespace WireMock.Extensions
namespace WireMock.Extensions;
internal static class TimeSettingsExtensions
{
internal static class TimeSettingsExtensions
public static bool IsValid(this ITimeSettings? settings)
{
public static bool IsValid([CanBeNull] this ITimeSettings settings)
if (settings == null)
{
if (settings == null)
{
return true;
}
var now = DateTime.Now;
var start = settings.Start != null ? settings.Start.Value : now;
DateTime end;
if (settings.End != null)
{
end = settings.End.Value;
}
else if (settings.TTL != null)
{
end = start.AddSeconds(settings.TTL.Value);
}
else
{
end = DateTime.MaxValue;
}
return now >= start && now <= end;
return true;
}
var now = DateTime.Now;
var start = settings.Start ?? now;
DateTime end;
if (settings.End != null)
{
end = settings.End.Value;
}
else if (settings.TTL != null)
{
end = start.AddSeconds(settings.TTL.Value);
}
else
{
end = DateTime.MaxValue;
}
return now >= start && now <= end;
}
}

View File

@@ -1,30 +1,28 @@
using System.Net.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Http
namespace WireMock.Http;
internal static class ByteArrayContentHelper
{
internal static class ByteArrayContentHelper
/// <summary>
/// Creates a ByteArrayContent object.
/// </summary>
/// <param name="content">The byte[] content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>ByteArrayContent</returns>
internal static ByteArrayContent Create(byte[] content, MediaTypeHeaderValue? contentType)
{
/// <summary>
/// Creates a ByteArrayContent object.
/// </summary>
/// <param name="content">The byte[] content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>ByteArrayContent</returns>
internal static ByteArrayContent Create([NotNull] byte[] content, [CanBeNull] MediaTypeHeaderValue contentType)
Guard.NotNull(content);
var byteContent = new ByteArrayContent(content);
if (contentType != null)
{
Guard.NotNull(content, nameof(content));
var byteContent = new ByteArrayContent(content);
if (contentType != null)
{
byteContent.Headers.Remove(HttpKnownHeaderNames.ContentType);
byteContent.Headers.ContentType = contentType;
}
return byteContent;
byteContent.Headers.Remove(HttpKnownHeaderNames.ContentType);
byteContent.Headers.ContentType = contentType;
}
return byteContent;
}
}
}

View File

@@ -3,64 +3,63 @@ using System.Net.Http;
using WireMock.HttpsCertificate;
using WireMock.Settings;
namespace WireMock.Http
namespace WireMock.Http;
internal static class HttpClientBuilder
{
internal static class HttpClientBuilder
public static HttpClient Build(HttpClientSettings settings)
{
public static HttpClient Build(HttpClientSettings settings)
{
#if NETSTANDARD || NETCOREAPP3_1 || NET5_0 || NET6_0
var handler = new HttpClientHandler
{
CheckCertificateRevocationList = false,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var handler = new HttpClientHandler
{
CheckCertificateRevocationList = false,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
#elif NET46
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
#else
var handler = new WebRequestHandler
{
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var handler = new WebRequestHandler
{
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
#endif
if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
{
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
}
handler.AllowAutoRedirect = settings.AllowAutoRedirect == true;
// If UseCookies enabled, httpClient ignores Cookie header
handler.UseCookies = false;
if (settings.WebProxySettings != null)
{
handler.UseProxy = true;
handler.Proxy = new WebProxy(settings.WebProxySettings.Address);
if (settings.WebProxySettings.UserName != null && settings.WebProxySettings.Password != null)
{
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
}
handler.AllowAutoRedirect = settings.AllowAutoRedirect == true;
// If UseCookies enabled, httpClient ignores Cookie header
handler.UseCookies = false;
if (settings.WebProxySettings != null)
{
handler.UseProxy = true;
handler.Proxy = new WebProxy(settings.WebProxySettings.Address);
if (settings.WebProxySettings.UserName != null && settings.WebProxySettings.Password != null)
{
handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
}
handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
}
}
#if !NETSTANDARD1_3
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
#endif
return new HttpClient(handler);
}
return HttpClientFactory2.Create(handler);
}
}

View File

@@ -0,0 +1,24 @@
using System.Net.Http;
namespace WireMock.Http;
internal static class HttpClientFactory2
{
public static HttpClient Create(params DelegatingHandler[] handlers)
{
#if NETSTANDARD1_3
return new HttpClient();
#else
return HttpClientFactory.Create(handlers);
#endif
}
public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
{
#if NETSTANDARD1_3
return new HttpClient(innerHandler);
#else
return HttpClientFactory.Create(innerHandler, handlers);
#endif
}
}

View File

@@ -1,122 +1,121 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
namespace WireMock.Http
namespace WireMock.Http;
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
{
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
// https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
private static readonly string[] RestrictedResponseHeaders =
{
// https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
private static readonly string[] RestrictedResponseHeaders =
{
Accept,
Connection,
ContentLength,
ContentType,
Date, // RFC1123Pattern
Expect,
Host,
IfModifiedSince,
Range,
Referer,
TransferEncoding,
UserAgent,
ProxyConnection
};
Accept,
Connection,
ContentLength,
ContentType,
Date, // RFC1123Pattern
Expect,
Host,
IfModifiedSince,
Range,
Referer,
TransferEncoding,
UserAgent,
ProxyConnection
};
/// <summary>Tests whether the specified HTTP header can be set for the response.</summary>
/// <param name="headerName">The header to test.</param>
/// <returns>true if the header is restricted; otherwise, false.</returns>
public static bool IsRestrictedResponseHeader(string headerName) => RestrictedResponseHeaders.Contains(headerName, StringComparer.OrdinalIgnoreCase);
/// <summary>Tests whether the specified HTTP header can be set for the response.</summary>
/// <param name="headerName">The header to test.</param>
/// <returns>true if the header is restricted; otherwise, false.</returns>
public static bool IsRestrictedResponseHeader(string headerName) => RestrictedResponseHeaders.Contains(headerName, StringComparer.OrdinalIgnoreCase);
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptPatch = "Accept-Patch";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string Age = "Age";
public const string Allow = "Allow";
public const string AltSvc = "Alt-Svc";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Cookie2 = "Cookie2";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expect = "Expect";
public const string Expires = "Expires";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string KeepAlive = "Keep-Alive";
public const string LastModified = "Last-Modified";
public const string Link = "Link";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Origin = "Origin";
public const string P3P = "P3P";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyConnection = "Proxy-Connection";
public const string PublicKeyPins = "Public-Key-Pins";
public const string Range = "Range";
public const string Referer = "Referer"; // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
public const string RetryAfter = "Retry-After";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string SetCookie2 = "Set-Cookie2";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string TSV = "TSV";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string WWWAuthenticate = "WWW-Authenticate";
public const string Warning = "Warning";
public const string XAspNetVersion = "X-AspNet-Version";
public const string XContentDuration = "X-Content-Duration";
public const string XContentTypeOptions = "X-Content-Type-Options";
public const string XFrameOptions = "X-Frame-Options";
public const string XMSEdgeRef = "X-MSEdge-Ref";
public const string XPoweredBy = "X-Powered-By";
public const string XRequestID = "X-Request-ID";
public const string XUACompatible = "X-UA-Compatible";
}
public const string Accept = "Accept";
public const string AcceptCharset = "Accept-Charset";
public const string AcceptEncoding = "Accept-Encoding";
public const string AcceptLanguage = "Accept-Language";
public const string AcceptPatch = "Accept-Patch";
public const string AcceptRanges = "Accept-Ranges";
public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
public const string AccessControlMaxAge = "Access-Control-Max-Age";
public const string Age = "Age";
public const string Allow = "Allow";
public const string AltSvc = "Alt-Svc";
public const string Authorization = "Authorization";
public const string CacheControl = "Cache-Control";
public const string Connection = "Connection";
public const string ContentDisposition = "Content-Disposition";
public const string ContentEncoding = "Content-Encoding";
public const string ContentLanguage = "Content-Language";
public const string ContentLength = "Content-Length";
public const string ContentLocation = "Content-Location";
public const string ContentMD5 = "Content-MD5";
public const string ContentRange = "Content-Range";
public const string ContentSecurityPolicy = "Content-Security-Policy";
public const string ContentType = "Content-Type";
public const string Cookie = "Cookie";
public const string Cookie2 = "Cookie2";
public const string Date = "Date";
public const string ETag = "ETag";
public const string Expect = "Expect";
public const string Expires = "Expires";
public const string From = "From";
public const string Host = "Host";
public const string IfMatch = "If-Match";
public const string IfModifiedSince = "If-Modified-Since";
public const string IfNoneMatch = "If-None-Match";
public const string IfRange = "If-Range";
public const string IfUnmodifiedSince = "If-Unmodified-Since";
public const string KeepAlive = "Keep-Alive";
public const string LastModified = "Last-Modified";
public const string Link = "Link";
public const string Location = "Location";
public const string MaxForwards = "Max-Forwards";
public const string Origin = "Origin";
public const string P3P = "P3P";
public const string Pragma = "Pragma";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyConnection = "Proxy-Connection";
public const string PublicKeyPins = "Public-Key-Pins";
public const string Range = "Range";
public const string Referer = "Referer"; // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
public const string RetryAfter = "Retry-After";
public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
public const string SecWebSocketKey = "Sec-WebSocket-Key";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string Server = "Server";
public const string SetCookie = "Set-Cookie";
public const string SetCookie2 = "Set-Cookie2";
public const string StrictTransportSecurity = "Strict-Transport-Security";
public const string TE = "TE";
public const string TSV = "TSV";
public const string Trailer = "Trailer";
public const string TransferEncoding = "Transfer-Encoding";
public const string Upgrade = "Upgrade";
public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
public const string UserAgent = "User-Agent";
public const string Vary = "Vary";
public const string Via = "Via";
public const string WWWAuthenticate = "WWW-Authenticate";
public const string Warning = "Warning";
public const string XAspNetVersion = "X-AspNet-Version";
public const string XContentDuration = "X-Content-Duration";
public const string XContentTypeOptions = "X-Content-Type-Options";
public const string XFrameOptions = "X-Frame-Options";
public const string XMSEdgeRef = "X-MSEdge-Ref";
public const string XPoweredBy = "X-Powered-By";
public const string XRequestID = "X-Request-ID";
public const string XUACompatible = "X-UA-Compatible";
}

View File

@@ -3,89 +3,87 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.Types;
using Stef.Validation;
using WireMock.Types;
namespace WireMock.Http
namespace WireMock.Http;
internal static class HttpRequestMessageHelper
{
internal static class HttpRequestMessageHelper
internal static HttpRequestMessage Create(IRequestMessage requestMessage, string url)
{
internal static HttpRequestMessage Create([NotNull] IRequestMessage requestMessage, [NotNull] string url)
Guard.NotNull(requestMessage);
Guard.NotNullOrEmpty(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
MediaTypeHeaderValue? contentType = null;
if (requestMessage.Headers != null && requestMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
{
Guard.NotNull(requestMessage, nameof(requestMessage));
Guard.NotNullOrEmpty(url, nameof(url));
var value = requestMessage.Headers[HttpKnownHeaderNames.ContentType].FirstOrDefault();
MediaTypeHeaderValue.TryParse(value, out contentType);
}
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Bytes:
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes, contentType);
break;
MediaTypeHeaderValue contentType = null;
if (requestMessage.Headers != null && requestMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
{
var value = requestMessage.Headers[HttpKnownHeaderNames.ContentType].FirstOrDefault();
MediaTypeHeaderValue.TryParse(value, out contentType);
}
case BodyType.Json:
httpRequestMessage.Content = StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType);
break;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Bytes:
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes, contentType);
break;
case BodyType.String:
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString, contentType);
break;
}
case BodyType.Json:
httpRequestMessage.Content = StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType);
break;
case BodyType.String:
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString, contentType);
break;
}
// Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority;
// Set other headers if present
if (requestMessage.Headers == null || requestMessage.Headers.Count == 0)
{
return httpRequestMessage;
}
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host, HttpKnownHeaderNames.ContentLength };
if (contentType != null)
{
// Content-Type should be set on the content
excludeHeaders.Add(HttpKnownHeaderNames.ContentType);
}
foreach (var header in requestMessage.Headers.Where(h => !excludeHeaders.Contains(h.Key, StringComparer.OrdinalIgnoreCase)))
{
// Skip if already added. We need to ToList() else calling httpRequestMessage.Headers.Contains() with a header starting with a ":" throws an exception.
if (httpRequestMessage.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
// Skip if already added. We need to ToList() else calling httpRequestMessage.Content.Headers.Contains(...) with a header starting with a ":" throws an exception.
if (httpRequestMessage.Content != null && httpRequestMessage.Content.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
// Try to add to request headers. If failed - try to add to content headers. If still fails, just ignore this header.
try
{
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
catch
{
// Just continue
}
}
// Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority;
// Set other headers if present
if (requestMessage.Headers == null || requestMessage.Headers.Count == 0)
{
return httpRequestMessage;
}
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host, HttpKnownHeaderNames.ContentLength };
if (contentType != null)
{
// Content-Type should be set on the content
excludeHeaders.Add(HttpKnownHeaderNames.ContentType);
}
foreach (var header in requestMessage.Headers.Where(h => !excludeHeaders.Contains(h.Key, StringComparer.OrdinalIgnoreCase)))
{
// Skip if already added. We need to ToList() else calling httpRequestMessage.Headers.Contains() with a header starting with a ":" throws an exception.
if (httpRequestMessage.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
// Skip if already added. We need to ToList() else calling httpRequestMessage.Content.Headers.Contains(...) with a header starting with a ":" throws an exception.
if (httpRequestMessage.Content != null && httpRequestMessage.Content.Headers.ToList().Any(h => string.Equals(h.Key, header.Key, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
// Try to add to request headers. If failed - try to add to content headers. If still fails, just ignore this header.
try
{
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
catch
{
// Just continue
}
}
return httpRequestMessage;
}
}

View File

@@ -1,18 +1,17 @@
namespace WireMock.Http
namespace WireMock.Http;
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
internal static class HttpRequestMethods
{
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
internal static class HttpRequestMethods
{
public const string CONNECT = "CONNECT";
public const string DELETE = "DELETE";
public const string GET = "GET";
public const string HEAD = "HEAD";
public const string OPTIONS = "OPTIONS";
public const string PATCH = "PATCH";
public const string POST = "POST";
public const string PUT = "PUT";
public const string TRACE = "TRACE";
}
public const string CONNECT = "CONNECT";
public const string DELETE = "DELETE";
public const string GET = "GET";
public const string HEAD = "HEAD";
public const string OPTIONS = "OPTIONS";
public const string PATCH = "PATCH";
public const string POST = "POST";
public const string PUT = "PUT";
public const string TRACE = "TRACE";
}

View File

@@ -5,60 +5,64 @@ using System.Net.Http;
using System.Threading.Tasks;
using WireMock.Util;
namespace WireMock.Http
namespace WireMock.Http;
internal static class HttpResponseMessageHelper
{
internal static class HttpResponseMessageHelper
public static async Task<ResponseMessage> CreateAsync(
HttpResponseMessage httpResponseMessage,
Uri requiredUri,
Uri originalUri,
bool deserializeJson,
bool decompressGzipAndDeflate)
{
public static async Task<ResponseMessage> CreateAsync(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri, bool deserializeJson, bool decompressGzipAndDeflate)
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
// Set both content and response headers, replacing URLs in values
var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>()).ToArray();
if (httpResponseMessage.Content != null)
{
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
// Set both content and response headers, replacing URLs in values
var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>()).ToArray();
if (httpResponseMessage.Content != null)
var stream = await httpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
IEnumerable<string>? contentTypeHeader = null;
if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)))
{
var stream = await httpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
IEnumerable<string> contentTypeHeader = null;
if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)))
{
contentTypeHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value;
}
IEnumerable<string> contentEncodingHeader = null;
if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)))
{
contentEncodingHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)).Value;
}
var bodyParserSettings = new BodyParserSettings
{
Stream = stream,
ContentType = contentTypeHeader?.FirstOrDefault(),
DeserializeJson = deserializeJson,
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
DecompressGZipAndDeflate = decompressGzipAndDeflate
};
responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
contentTypeHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value;
}
foreach (var header in headers)
IEnumerable<string>? contentEncodingHeader = null;
if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)))
{
// If Location header contains absolute redirect URL, and base URL is one that we proxy to,
// we need to replace it to original one.
if (string.Equals(header.Key, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase)
&& Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri)
&& string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase))
{
var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery);
responseMessage.AddHeader(header.Key, replacedLocationUri.ToString());
}
else
{
responseMessage.AddHeader(header.Key, header.Value.ToArray());
}
contentEncodingHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)).Value;
}
return responseMessage;
var bodyParserSettings = new BodyParserSettings
{
Stream = stream,
ContentType = contentTypeHeader?.FirstOrDefault(),
DeserializeJson = deserializeJson,
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
DecompressGZipAndDeflate = decompressGzipAndDeflate
};
responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
}
foreach (var header in headers)
{
// If Location header contains absolute redirect URL, and base URL is one that we proxy to,
// we need to replace it to original one.
if (string.Equals(header.Key, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase)
&& Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri)
&& string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase))
{
var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery);
responseMessage.AddHeader(header.Key, replacedLocationUri.ToString());
}
else
{
responseMessage.AddHeader(header.Key, header.Value.ToArray());
}
}
return responseMessage;
}
}

View File

@@ -1,25 +1,23 @@
using System.Net.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Http
{
internal static class StringContentHelper
{
/// <summary>
/// Creates a StringContent object.
/// </summary>
/// <param name="content">The string content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>StringContent</returns>
internal static StringContent Create([NotNull] string content, [CanBeNull] MediaTypeHeaderValue contentType)
{
Guard.NotNull(content, nameof(content));
namespace WireMock.Http;
var stringContent = new StringContent(content);
stringContent.Headers.ContentType = contentType;
return stringContent;
}
internal static class StringContentHelper
{
/// <summary>
/// Creates a StringContent object.
/// </summary>
/// <param name="content">The string content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>StringContent</returns>
internal static StringContent Create(string content, MediaTypeHeaderValue? contentType)
{
Guard.NotNull(content);
var stringContent = new StringContent(content);
stringContent.Headers.ContentType = contentType;
return stringContent;
}
}

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Models;
using WireMock.Settings;
using WireMock.Transformers;
@@ -11,75 +11,74 @@ using WireMock.Transformers.Handlebars;
using WireMock.Transformers.Scriban;
using WireMock.Types;
using WireMock.Util;
using Stef.Validation;
namespace WireMock.Http
namespace WireMock.Http;
internal class WebhookSender
{
internal class WebhookSender
private const string ClientIp = "::1";
private readonly WireMockServerSettings _settings;
public WebhookSender(WireMockServerSettings settings)
{
private const string ClientIp = "::1";
_settings = Guard.NotNull(settings);
}
private readonly WireMockServerSettings _settings;
public Task<HttpResponseMessage> SendAsync(HttpClient client, IMapping mapping, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
{
Guard.NotNull(client);
Guard.NotNull(mapping);
Guard.NotNull(request);
Guard.NotNull(originalRequestMessage);
Guard.NotNull(originalResponseMessage);
public WebhookSender(WireMockServerSettings settings)
IBodyData? bodyData;
IDictionary<string, WireMockList<string>>? headers;
if (request.UseTransformer == true)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
}
public Task<HttpResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] IWebhookRequest request, [NotNull] IRequestMessage originalRequestMessage, [NotNull] IResponseMessage originalResponseMessage)
{
Guard.NotNull(client, nameof(client));
Guard.NotNull(request, nameof(request));
Guard.NotNull(originalRequestMessage, nameof(originalRequestMessage));
Guard.NotNull(originalResponseMessage, nameof(originalResponseMessage));
IBodyData bodyData;
IDictionary<string, WireMockList<string>> headers;
if (request.UseTransformer == true)
ITransformer responseMessageTransformer;
switch (request.TransformerType)
{
ITransformer responseMessageTransformer;
switch (request.TransformerType)
{
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(_settings.FileSystemHandler, _settings.HandlebarsRegistrationCallback);
responseMessageTransformer = new Transformer(factoryHandlebars);
break;
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(_settings.FileSystemHandler, _settings.HandlebarsRegistrationCallback);
responseMessageTransformer = new Transformer(factoryHandlebars);
break;
case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, request.TransformerType);
responseMessageTransformer = new Transformer(factoryDotLiquid);
break;
case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, request.TransformerType);
responseMessageTransformer = new Transformer(factoryDotLiquid);
break;
default:
throw new NotImplementedException($"TransformerType '{request.TransformerType}' is not supported.");
}
(bodyData, headers) = responseMessageTransformer.Transform(originalRequestMessage, originalResponseMessage, request.BodyData, request.Headers, request.TransformerReplaceNodeOptions);
}
else
{
bodyData = request.BodyData;
headers = request.Headers;
default:
throw new NotImplementedException($"TransformerType '{request.TransformerType}' is not supported.");
}
// Create RequestMessage
var requestMessage = new RequestMessage(
new UrlDetails(request.Url),
request.Method,
ClientIp,
bodyData,
headers?.ToDictionary(x => x.Key, x => x.Value.ToArray())
)
{
DateTime = DateTime.UtcNow
};
// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, request.Url);
// Call the URL
return client.SendAsync(httpRequestMessage);
(bodyData, headers) = responseMessageTransformer.Transform(mapping, originalRequestMessage, originalResponseMessage, request.BodyData, request.Headers, request.TransformerReplaceNodeOptions);
}
else
{
bodyData = request.BodyData;
headers = request.Headers;
}
// Create RequestMessage
var requestMessage = new RequestMessage(
new UrlDetails(request.Url),
request.Method,
ClientIp,
bodyData,
headers?.ToDictionary(x => x.Key, x => x.Value.ToArray())
)
{
DateTime = DateTime.UtcNow
};
// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, request.Url);
// Call the URL
return client.SendAsync(httpRequestMessage);
}
}

View File

@@ -2,90 +2,42 @@ using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
namespace WireMock.HttpsCertificate;
internal static class CertificateLoader
{
internal static class CertificateLoader
private const string ExtensionPem = ".PEM";
/// <summary>
/// Used by the WireMock.Net server
/// </summary>
public static X509Certificate2 LoadCertificate(
string? storeName,
string? storeLocation,
string? thumbprintOrSubjectName,
string? filePath,
string? passwordOrKey,
string host)
{
/// <summary>
/// Used by the WireMock.Net server
/// </summary>
public static X509Certificate2 LoadCertificate(
string storeName,
string storeLocation,
string thumbprintOrSubjectName,
string filePath,
string password,
string host)
if (!string.IsNullOrEmpty(storeName) && !string.IsNullOrEmpty(storeLocation))
{
if (!string.IsNullOrEmpty(storeName) && !string.IsNullOrEmpty(storeLocation))
{
var thumbprintOrSubjectNameOrHost = thumbprintOrSubjectName ?? host;
var thumbprintOrSubjectNameOrHost = thumbprintOrSubjectName ?? host;
var certStore = new X509Store((StoreName)Enum.Parse(typeof(StoreName), storeName), (StoreLocation)Enum.Parse(typeof(StoreLocation), storeLocation));
try
{
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by Thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// Fallback to SubjectName
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException($"No Certificate found with in store '{storeName}', location '{storeLocation}' for Thumbprint or SubjectName '{thumbprintOrSubjectNameOrHost}'.");
}
}
// Use the first matching certificate.
return matchingCertificates[0];
}
finally
{
#if NETSTANDARD || NET46
certStore.Dispose();
#else
certStore.Close();
#endif
}
}
if (!string.IsNullOrEmpty(filePath) && !string.IsNullOrEmpty(password))
{
return new X509Certificate2(filePath, password);
}
if (!string.IsNullOrEmpty(filePath))
{
return new X509Certificate2(filePath);
}
throw new InvalidOperationException("X509StoreName and X509StoreLocation OR X509CertificateFilePath are mandatory. Note that X509CertificatePassword is optional.");
}
/// <summary>
/// Used for Proxy
/// </summary>
public static X509Certificate2 LoadCertificate(string thumbprintOrSubjectName)
{
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
var certStore = new X509Store((StoreName)Enum.Parse(typeof(StoreName), storeName), (StoreLocation)Enum.Parse(typeof(StoreLocation), storeLocation));
try
{
// Certificate must be in the local machine store
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by Thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectName, false);
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// Fallback to SubjectName
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectName, false);
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectNameOrHost, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException("No certificate found with specified Thumbprint or SubjectName.", thumbprintOrSubjectName);
throw new FileNotFoundException($"No Certificate found with in store '{storeName}', location '{storeLocation}' for Thumbprint or SubjectName '{thumbprintOrSubjectNameOrHost}'.");
}
}
@@ -101,5 +53,76 @@ namespace WireMock.HttpsCertificate
#endif
}
}
if (!string.IsNullOrEmpty(filePath))
{
if (filePath!.EndsWith(ExtensionPem, StringComparison.OrdinalIgnoreCase))
{
// PEM logic based on: https://www.scottbrady91.com/c-sharp/pem-loading-in-dotnet-core-and-dotnet
#if NET5_0_OR_GREATER
if (!string.IsNullOrEmpty(passwordOrKey))
{
var certPem = File.ReadAllText(filePath);
var cert = X509Certificate2.CreateFromPem(certPem, passwordOrKey);
const string defaultPasswordPem = "WireMock.Net";
return new X509Certificate2(cert.Export(X509ContentType.Pfx, defaultPasswordPem), defaultPasswordPem);
}
return X509Certificate2.CreateFromPemFile(filePath);
#elif NETCOREAPP3_1
var cert = new X509Certificate2(filePath);
if (!string.IsNullOrEmpty(passwordOrKey))
{
var key = System.Security.Cryptography.ECDsa.Create()!;
key.ImportECPrivateKey(System.Text.Encoding.UTF8.GetBytes(passwordOrKey), out _);
return cert.CopyWithPrivateKey(key);
}
return cert;
#else
throw new InvalidOperationException("Loading a PEM Certificate is only supported for .NET Core App 3.1, .NET 5.0 and higher.");
#endif
}
return !string.IsNullOrEmpty(passwordOrKey) ? new X509Certificate2(filePath, passwordOrKey) : new X509Certificate2(filePath);
}
throw new InvalidOperationException("X509StoreName and X509StoreLocation OR X509CertificateFilePath are mandatory. Note that X509CertificatePassword is optional.");
}
/// <summary>
/// Used for Proxy
/// </summary>
public static X509Certificate2 LoadCertificate(string thumbprintOrSubjectName)
{
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
// Certificate must be in the local machine store
certStore.Open(OpenFlags.ReadOnly);
// Attempt to find by Thumbprint first
var matchingCertificates = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// Fallback to SubjectName
matchingCertificates = certStore.Certificates.Find(X509FindType.FindBySubjectName, thumbprintOrSubjectName, false);
if (matchingCertificates.Count == 0)
{
// No certificates matched the search criteria.
throw new FileNotFoundException("No certificate found with specified Thumbprint or SubjectName.", thumbprintOrSubjectName);
}
}
// Use the first matching certificate.
return matchingCertificates[0];
}
finally
{
#if NETSTANDARD || NET46
certStore.Dispose();
#else
certStore.Close();
#endif
}
}
}

View File

@@ -1,16 +1,16 @@
using System;
using System;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
namespace WireMock.HttpsCertificate;
/// <summary>
/// Only used for NetStandard 1.3
/// </summary>
internal static class PublicCertificateHelper
{
/// <summary>
/// Only used for NetStandard 1.3
/// </summary>
internal static class PublicCertificateHelper
{
// 1] Generate using https://www.pluralsight.com/blog/software-development/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net
// 2] Converted to Base64
private const string Data = @"MIIQMgIBAzCCD+4GCSqGSIb3DQEHAaCCD98Egg/bMIIP1zCCCogGCSqGSIb3DQEHAaCCCnkEggp1
// 1] Generate using https://www.pluralsight.com/blog/software-development/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net
// 2] Converted to Base64
private const string Data = @"MIIQMgIBAzCCD+4GCSqGSIb3DQEHAaCCD98Egg/bMIIP1zCCCogGCSqGSIb3DQEHAaCCCnkEggp1
MIIKcTCCCm0GCyqGSIb3DQEMCgECoIIJfjCCCXowHAYKKoZIhvcNAQwBAzAOBAi1j9x1jTfUewIC
B9AEgglYa48lP16+isiGEVT7zwN3XwaPwPOHZcQ7tRA/DA8LZnZbwU7XhtPObF5bZcHn4engX2An
ISFpe2S5XJ7BfHmsGOO7Bxj6C2IcZIPTefvAd9vWE0WUAGN11SLhJ3fB/ZRt3Nys7JCJzywQCkYK
@@ -85,10 +85,9 @@ TLNGa+UmMnPsnBjlAJ6l9VPsa4uJM2DIQKtZXWq4DkhSAYKF6joIP7nKMDswHzAHBgUrDgMCGgQU
wTM1Z+CJZG9xAcf1zAVGl4ggYyYEFGBFyJ8VBwijS2zy1qwN1WYGtcWoAgIH0A==
";
public static X509Certificate2 GetX509Certificate2()
{
byte[] data = Convert.FromBase64String(Data);
return new X509Certificate2(data);
}
public static X509Certificate2 GetX509Certificate2()
{
byte[] data = Convert.FromBase64String(Data);
return new X509Certificate2(data);
}
}

View File

@@ -1,4 +1,3 @@
using JetBrains.Annotations;
using System;
using System.Threading.Tasks;
using WireMock.Matchers.Request;
@@ -6,130 +5,125 @@ using WireMock.Models;
using WireMock.ResponseProviders;
using WireMock.Settings;
namespace WireMock
namespace WireMock;
/// <summary>
/// The IMapping interface.
/// </summary>
public interface IMapping
{
/// <summary>
/// The IMapping interface.
/// Gets the unique identifier.
/// </summary>
public interface IMapping
{
/// <summary>
/// Gets the unique identifier.
/// </summary>
Guid Guid { get; }
Guid Guid { get; }
/// <summary>
/// Gets the TimeSettings (Start, End and TTL).
/// </summary>
ITimeSettings TimeSettings { get; }
/// <summary>
/// Gets the TimeSettings (Start, End and TTL).
/// </summary>
ITimeSettings? TimeSettings { get; }
/// <summary>
/// Gets the unique title.
/// </summary>
string Title { get; }
/// <summary>
/// Gets the unique title.
/// </summary>
string? Title { get; }
/// <summary>
/// Gets the description.
/// </summary>
string Description { get; }
/// <summary>
/// Gets the description.
/// </summary>
string? Description { get; }
/// <summary>
/// The full filename path for this mapping (only defined for static mappings).
/// </summary>
string Path { get; set; }
/// <summary>
/// The full filename path for this mapping (only defined for static mappings).
/// </summary>
string? Path { get; set; }
/// <summary>
/// Gets the priority. (A low value means higher priority.)
/// </summary>
int Priority { get; }
/// <summary>
/// Gets the priority. (A low value means higher priority.)
/// </summary>
int Priority { get; }
/// <summary>
/// Scenario.
/// </summary>
[CanBeNull]
string Scenario { get; }
/// <summary>
/// Scenario.
/// </summary>
string? Scenario { get; }
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
[CanBeNull]
string ExecutionConditionState { get; }
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
string? ExecutionConditionState { get; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null, state will not be changed.
/// </summary>
[CanBeNull]
string NextState { get; }
/// <summary>
/// The next state which will be signaled after the current mapping execution.
/// In case the value is null, state will not be changed.
/// </summary>
string? NextState { get; }
/// <summary>
/// The number of times this match should be matched before the state will be changed to the next state.
/// </summary>
[CanBeNull]
int? StateTimes { get; }
/// <summary>
/// The number of times this match should be matched before the state will be changed to the next state.
/// </summary>
int? StateTimes { get; }
/// <summary>
/// The Request matcher.
/// </summary>
IRequestMatcher RequestMatcher { get; }
/// <summary>
/// The Request matcher.
/// </summary>
IRequestMatcher RequestMatcher { get; }
/// <summary>
/// The Provider.
/// </summary>
IResponseProvider Provider { get; }
/// <summary>
/// The Provider.
/// </summary>
IResponseProvider Provider { get; }
/// <summary>
/// The WireMockServerSettings.
/// </summary>
WireMockServerSettings Settings { get; }
/// <summary>
/// The WireMockServerSettings.
/// </summary>
WireMockServerSettings Settings { get; }
/// <summary>
/// Is State started ?
/// </summary>
bool IsStartState { get; }
/// <summary>
/// Is State started ?
/// </summary>
bool IsStartState { get; }
/// <summary>
/// Gets a value indicating whether this mapping is an Admin Interface.
/// </summary>
/// <value>
/// <c>true</c> if this mapping is an Admin Interface; otherwise, <c>false</c>.
/// </value>
bool IsAdminInterface { get; }
/// <summary>
/// Gets a value indicating whether this mapping is an Admin Interface.
/// </summary>
/// <value>
/// <c>true</c> if this mapping is an Admin Interface; otherwise, <c>false</c>.
/// </value>
bool IsAdminInterface { get; }
/// <summary>
/// Gets a value indicating whether this mapping is a Proxy Mapping.
/// </summary>
/// <value>
/// <c>true</c> if this mapping is a Proxy Mapping; otherwise, <c>false</c>.
/// </value>
bool IsProxy { get; }
/// <summary>
/// Gets a value indicating whether this mapping is a Proxy Mapping.
/// </summary>
/// <value>
/// <c>true</c> if this mapping is a Proxy Mapping; otherwise, <c>false</c>.
/// </value>
bool IsProxy { get; }
/// <summary>
/// Gets a value indicating whether this mapping to be logged.
/// </summary>
/// <value>
/// <c>true</c> if this mapping to be logged; otherwise, <c>false</c>.
/// </value>
bool LogMapping { get; }
/// <summary>
/// Gets a value indicating whether this mapping to be logged.
/// </summary>
/// <value>
/// <c>true</c> if this mapping to be logged; otherwise, <c>false</c>.
/// </value>
bool LogMapping { get; }
/// <summary>
/// The Webhooks.
/// </summary>
IWebhook[] Webhooks { get; }
/// <summary>
/// The Webhooks.
/// </summary>
IWebhook[]? Webhooks { get; }
/// <summary>
/// ProvideResponseAsync
/// </summary>
/// <param name="requestMessage">The request message.</param>
/// <returns>The <see cref="ResponseMessage"/> including a new (optional) <see cref="IMapping"/>.</returns>
Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
/// <summary>
/// ProvideResponseAsync
/// </summary>
/// <param name="requestMessage">The request message.</param>
/// <returns>The <see cref="ResponseMessage"/> including a new (optional) <see cref="IMapping"/>.</returns>
Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
/// <summary>
/// Gets the RequestMatchResult based on the RequestMessage.
/// </summary>
/// <param name="requestMessage">The request message.</param>
/// <param name="nextState">The Next State.</param>
/// <returns>The <see cref="IRequestMatchResult"/>.</returns>
IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, [CanBeNull] string nextState);
}
/// <summary>
/// Gets the RequestMatchResult based on the RequestMessage.
/// </summary>
/// <param name="requestMessage">The request message.</param>
/// <param name="nextState">The Next State.</param>
/// <returns>The <see cref="IRequestMatchResult"/>.</returns>
IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState);
}

View File

@@ -1,38 +1,37 @@
using System;
using System;
using WireMock.Matchers.Request;
namespace WireMock.Logging
namespace WireMock.Logging;
/// <summary>
/// LogEntry
/// </summary>
public class LogEntry : ILogEntry
{
/// <summary>
/// LogEntry
/// </summary>
public class LogEntry : ILogEntry
{
/// <inheritdoc cref="ILogEntry.Guid" />
public Guid Guid { get; set; }
/// <inheritdoc cref="ILogEntry.Guid" />
public Guid Guid { get; set; }
/// <inheritdoc cref="ILogEntry.RequestMessage" />
public IRequestMessage RequestMessage { get; set; }
/// <inheritdoc cref="ILogEntry.RequestMessage" />
public IRequestMessage RequestMessage { get; set; }
/// <inheritdoc cref="ILogEntry.ResponseMessage" />
public IResponseMessage ResponseMessage { get; set; }
/// <inheritdoc cref="ILogEntry.ResponseMessage" />
public IResponseMessage ResponseMessage { get; set; }
/// <inheritdoc cref="ILogEntry.RequestMatchResult" />
public IRequestMatchResult RequestMatchResult { get; set; }
/// <inheritdoc cref="ILogEntry.RequestMatchResult" />
public IRequestMatchResult RequestMatchResult { get; set; }
/// <inheritdoc cref="ILogEntry.MappingGuid" />
public Guid? MappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.MappingGuid" />
public Guid? MappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.MappingTitle" />
public string MappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.MappingTitle" />
public string? MappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingGuid" />
public Guid? PartialMappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingGuid" />
public Guid? PartialMappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingTitle" />
public string PartialMappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingTitle" />
public string? PartialMappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
public IRequestMatchResult PartialMatchResult { get; set; }
}
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
public IRequestMatchResult PartialMatchResult { get; set; }
}

View File

@@ -1,4 +1,4 @@
using Newtonsoft.Json;
using Newtonsoft.Json;
using System;
using WireMock.Admin.Requests;
@@ -51,7 +51,7 @@ namespace WireMock.Logging
{
ae.Handle(ex =>
{
Console.WriteLine(Format("Error", "Exception {0}", exception.Message));
Console.WriteLine(Format("Error", "Exception {0}", ex.Message));
return true;
});
}

View File

@@ -1,149 +1,147 @@
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Matchers.Request;
using WireMock.Models;
using WireMock.ResponseProviders;
using WireMock.Settings;
namespace WireMock
namespace WireMock;
/// <summary>
/// The Mapping.
/// </summary>
public class Mapping : IMapping
{
/// <inheritdoc />
public Guid Guid { get; }
/// <inheritdoc />
public string? Title { get; }
/// <inheritdoc />
public string? Description { get; }
/// <inheritdoc />
public string? Path { get; set; }
/// <inheritdoc />
public int Priority { get; }
/// <inheritdoc />
public string? Scenario { get; }
/// <inheritdoc />
public string? ExecutionConditionState { get; }
/// <inheritdoc />
public string? NextState { get; }
/// <inheritdoc />
public int? StateTimes { get; }
/// <inheritdoc />
public IRequestMatcher RequestMatcher { get; }
/// <inheritdoc />
public IResponseProvider Provider { get; }
/// <inheritdoc />
public WireMockServerSettings Settings { get; }
/// <inheritdoc />
public bool IsStartState => Scenario == null || Scenario != null && NextState != null && ExecutionConditionState == null;
/// <inheritdoc />
public bool IsAdminInterface => Provider is DynamicResponseProvider or DynamicAsyncResponseProvider or ProxyAsyncResponseProvider;
/// <inheritdoc />
public bool IsProxy => Provider is ProxyAsyncResponseProvider;
/// <inheritdoc />
public bool LogMapping => Provider is not (DynamicResponseProvider or DynamicAsyncResponseProvider);
/// <inheritdoc />
public IWebhook[]? Webhooks { get; }
/// <inheritdoc />
public ITimeSettings? TimeSettings { get; }
/// <summary>
/// The Mapping.
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
public class Mapping : IMapping
/// <param name="guid">The unique identifier.</param>
/// <param name="title">The unique title (can be null).</param>
/// <param name="description">The description (can be null).</param>
/// <param name="path">The full file path from this mapping title (can be null).</param>
/// <param name="settings">The WireMockServerSettings.</param>
/// <param name="requestMatcher">The request matcher.</param>
/// <param name="provider">The provider.</param>
/// <param name="priority">The priority for this mapping.</param>
/// <param name="scenario">The scenario. [Optional]</param>
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
/// <param name="webhooks">The Webhooks. [Optional]</param>
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
public Mapping(
Guid guid,
string? title,
string? description,
string? path,
WireMockServerSettings settings,
IRequestMatcher requestMatcher,
IResponseProvider provider,
int priority,
string? scenario,
string? executionConditionState,
string? nextState,
int? stateTimes,
IWebhook[]? webhooks,
ITimeSettings? timeSettings)
{
/// <inheritdoc />
public Guid Guid { get; }
Guid = guid;
Title = title;
Description = description;
Path = path;
Settings = settings;
RequestMatcher = requestMatcher;
Provider = provider;
Priority = priority;
Scenario = scenario;
ExecutionConditionState = executionConditionState;
NextState = nextState;
StateTimes = stateTimes;
Webhooks = webhooks;
TimeSettings = timeSettings;
}
/// <inheritdoc />
public string Title { get; }
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
{
return Provider.ProvideResponseAsync(this, requestMessage, Settings);
}
/// <inheritdoc />
public string Description { get; }
/// <inheritdoc cref="IMapping.GetRequestMatchResult" />
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState)
{
var result = new RequestMatchResult();
/// <inheritdoc />
public string Path { get; set; }
RequestMatcher.GetMatchingScore(requestMessage, result);
/// <inheritdoc />
public int Priority { get; }
/// <inheritdoc />
public string Scenario { get; }
/// <inheritdoc />
public string ExecutionConditionState { get; }
/// <inheritdoc />
public string NextState { get; }
/// <inheritdoc />
public int? StateTimes { get; }
/// <inheritdoc />
public IRequestMatcher RequestMatcher { get; }
/// <inheritdoc />
public IResponseProvider Provider { get; }
/// <inheritdoc />
public WireMockServerSettings Settings { get; }
/// <inheritdoc />
public bool IsStartState => Scenario == null || Scenario != null && NextState != null && ExecutionConditionState == null;
/// <inheritdoc />
public bool IsAdminInterface => Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider || Provider is ProxyAsyncResponseProvider;
/// <inheritdoc />
public bool IsProxy => Provider is ProxyAsyncResponseProvider;
/// <inheritdoc />
public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider);
/// <inheritdoc />
public IWebhook[] Webhooks { get; }
/// <inheritdoc />
public ITimeSettings TimeSettings { get; }
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
/// <param name="guid">The unique identifier.</param>
/// <param name="title">The unique title (can be null).</param>
/// <param name="description">The description (can be null).</param>
/// <param name="path">The full file path from this mapping title (can be null).</param>
/// <param name="settings">The WireMockServerSettings.</param>
/// <param name="requestMatcher">The request matcher.</param>
/// <param name="provider">The provider.</param>
/// <param name="priority">The priority for this mapping.</param>
/// <param name="scenario">The scenario. [Optional]</param>
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
/// <param name="webhooks">The Webhooks. [Optional]</param>
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
public Mapping(
Guid guid,
string? title,
string? description,
string? path,
WireMockServerSettings settings,
IRequestMatcher requestMatcher,
IResponseProvider provider,
int priority,
string? scenario,
string? executionConditionState,
string? nextState,
int? stateTimes,
IWebhook[]? webhooks,
ITimeSettings? timeSettings)
// Only check state if Scenario is defined
if (Scenario != null)
{
Guid = guid;
Title = title;
Description = description;
Path = path;
Settings = settings;
RequestMatcher = requestMatcher;
Provider = provider;
Priority = priority;
Scenario = scenario;
ExecutionConditionState = executionConditionState;
NextState = nextState;
StateTimes = stateTimes;
Webhooks = webhooks;
TimeSettings = timeSettings;
var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
matcher.GetMatchingScore(requestMessage, result);
//// If ExecutionConditionState is null, this means that request is the start from a scenario. So just return.
//if (ExecutionConditionState != null)
//{
// // ExecutionConditionState is not null, so get score for matching with the nextState.
// var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
// matcher.GetMatchingScore(requestMessage, result);
//}
}
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
{
return Provider.ProvideResponseAsync(requestMessage, Settings);
}
/// <inheritdoc cref="IMapping.GetRequestMatchResult" />
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string nextState)
{
var result = new RequestMatchResult();
RequestMatcher.GetMatchingScore(requestMessage, result);
// Only check state if Scenario is defined
if (Scenario != null)
{
var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
matcher.GetMatchingScore(requestMessage, result);
//// If ExecutionConditionState is null, this means that request is the start from a scenario. So just return.
//if (ExecutionConditionState != null)
//{
// // ExecutionConditionState is not null, so get score for matching with the nextState.
// var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
// matcher.GetMatchingScore(requestMessage, result);
//}
}
return result;
}
return result;
}
}

View File

@@ -1,89 +1,110 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using WireMock.Util;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// Generic AbstractJsonPartialMatcher
/// </summary>
public abstract class AbstractJsonPartialMatcher : JsonMatcher
{
/// <summary>
/// Generic AbstractJsonPartialMatcher
/// Support Regex
/// </summary>
public abstract class AbstractJsonPartialMatcher : JsonMatcher
public bool Regex { get; }
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException)
{
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
protected AbstractJsonPartialMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
protected AbstractJsonPartialMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(matchBehaviour, value, ignoreCase, throwException)
{
}
/// <inheritdoc />
protected override bool IsMatch(JToken value, JToken input)
{
if (value == null || value == input)
{
return true;
}
if (input == null || value.Type != input.Type)
{
return false;
}
switch (value.Type)
{
case JTokenType.Object:
var nestedValues = value.ToObject<Dictionary<string, JToken>>();
return nestedValues?.Any() != true ||
nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
case JTokenType.Array:
var valuesArray = value.ToObject<JToken[]>();
var tokenArray = input.ToObject<JToken[]>();
if (valuesArray?.Any() != true)
{
return true;
}
return tokenArray?.Any() == true &&
valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
default:
return IsMatch(value.ToString(), input.ToString());
}
}
/// <summary>
/// Check if two strings are a match (matching can be done exact or wildcard)
/// </summary>
protected abstract bool IsMatch(string value, string input);
Regex = regex;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException)
{
Regex = regex;
}
/// <summary>
/// Initializes a new instance of the <see cref="AbstractJsonPartialMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException)
{
Regex = regex;
}
/// <inheritdoc />
protected override bool IsMatch(JToken? value, JToken? input)
{
if (value == null || value == input)
{
return true;
}
if (Regex && value.Type == JTokenType.String && input != null)
{
var valueAsString = value.ToString();
var (valid, result) = RegexUtils.MatchRegex(valueAsString, input.ToString());
if (valid)
{
return result;
}
}
if (input == null || value.Type != input.Type)
{
return false;
}
switch (value.Type)
{
case JTokenType.Object:
var nestedValues = value.ToObject<Dictionary<string, JToken>>();
return nestedValues?.Any() != true ||
nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
case JTokenType.Array:
var valuesArray = value.ToObject<JToken[]>();
var tokenArray = input.ToObject<JToken[]>();
if (valuesArray?.Any() != true)
{
return true;
}
return tokenArray?.Any() == true &&
valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
default:
return IsMatch(value.ToString(), input.ToString());
}
}
/// <summary>
/// Check if two strings are a match (matching can be done exact or wildcard)
/// </summary>
protected abstract bool IsMatch(string value, string input);
}

View File

@@ -3,75 +3,74 @@ using AnyOfTypes;
using JetBrains.Annotations;
using WireMock.Models;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// ContentTypeMatcher which accepts also all charsets
/// </summary>
/// <seealso cref="RegexMatcher" />
public class ContentTypeMatcher : WildcardMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary>
/// ContentTypeMatcher which accepts also all charsets
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <seealso cref="RegexMatcher" />
public class ContentTypeMatcher : WildcardMatcher
/// <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)
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher([NotNull] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher([NotNull] AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false, bool throwException = false) :
base(matchBehaviour, patterns, ignoreCase, throwException)
{
_patterns = patterns;
}
/// <inheritdoc cref="RegexMatcher.IsMatch"/>
public override double IsMatch(string input)
{
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
}
return base.IsMatch(contentType.MediaType);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public override AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public override string Name => "ContentTypeMatcher";
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <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)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false, bool throwException = false) :
base(matchBehaviour, patterns, ignoreCase, throwException)
{
_patterns = patterns;
}
/// <inheritdoc cref="RegexMatcher.IsMatch"/>
public override double IsMatch(string? input)
{
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
}
return base.IsMatch(contentType.MediaType);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public override AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public override string Name => "ContentTypeMatcher";
}

View File

@@ -1,67 +1,69 @@
using System.Linq;
using AnyOfTypes;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using Stef.Validation;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// ExactMatcher
/// </summary>
/// <seealso cref="IStringMatcher" />
public class ExactMatcher : IStringMatcher
{
private readonly AnyOf<string, StringPattern>[] _values;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// ExactMatcher
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <seealso cref="IStringMatcher" />
public class ExactMatcher : IStringMatcher
/// <param name="values">The values.</param>
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
{
private readonly AnyOf<string, StringPattern>[] _values;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="values">The values.</param>
public ExactMatcher([NotNull] params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, values)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="values">The values.</param>
public ExactMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf<string, StringPattern>[] values)
{
Guard.NotNull(values, nameof(values));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_values = values;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
if (_values.Length == 1)
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values[0].GetPattern() == input));
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values.Select(v => v.GetPattern()).Contains(input)));
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _values;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactMatcher";
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="values">The values.</param>
public ExactMatcher(
MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] values)
{
_values = Guard.NotNull(values);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string? input)
{
double score = MatchScores.ToScore(_values.Select(v => v.GetPattern() == input).ToArray(), MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _values;
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactMatcher";
}

View File

@@ -1,83 +1,86 @@
using JetBrains.Annotations;
using System.Linq;
using Stef.Validation;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// ExactObjectMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
{
/// <summary>
/// ExactObjectMatcher
/// Gets the value as object.
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
public object? ValueAsObject { get; }
/// <summary>
/// Gets the value as byte[].
/// </summary>
public byte[]? ValueAsBytes { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher(object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
/// <summary>
/// Gets the value as object.
/// </summary>
public object ValueAsObject { get; }
/// <summary>
/// Gets the value as byte[].
/// </summary>
public byte[] ValueAsBytes { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
{
Guard.NotNull(value, nameof(value));
ValueAsObject = value;
MatchBehaviour = matchBehaviour;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value, bool throwException = false)
{
Guard.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
ValueAsBytes = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool equals = ValueAsObject != null ? Equals(ValueAsObject, input) : ValueAsBytes.SequenceEqual((byte[])input);
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactObjectMatcher";
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, object value)
{
ValueAsObject = Guard.NotNull(value);
MatchBehaviour = matchBehaviour;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher(byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, byte[] value, bool throwException = false)
{
ValueAsBytes = Guard.NotNull(value);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object? input)
{
bool equals = false;
if (ValueAsObject != null)
{
equals = Equals(ValueAsObject, input);
}
else if (input != null)
{
equals = ValueAsBytes?.SequenceEqual((byte[])input) == true;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactObjectMatcher";
}

View File

@@ -1,11 +1,10 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
}
}

View File

@@ -1,14 +1,13 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IIgnoreCaseMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// IIgnoreCaseMatcher
/// Ignore the case from the pattern.
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// Ignore the case from the pattern.
/// </summary>
bool IgnoreCase { get; }
}
bool IgnoreCase { get; }
}

View File

@@ -1,23 +1,22 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IMatcher
/// </summary>
public interface IMatcher
{
/// <summary>
/// IMatcher
/// Gets the name.
/// </summary>
public interface IMatcher
{
/// <summary>
/// Gets the name.
/// </summary>
string Name { get; }
string Name { get; }
/// <summary>
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
}
/// <summary>
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
}

View File

@@ -1,15 +1,14 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IObjectMatcher
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// IObjectMatcher
/// Determines whether the specified input is match.
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(object input);
}
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(object? input);
}

View File

@@ -1,25 +1,29 @@
using AnyOfTypes;
using WireMock.Models;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IStringMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IStringMatcher : IMatcher
{
/// <summary>
/// IStringMatcher
/// Determines whether the specified input is match.
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IStringMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string input);
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string? input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
AnyOf<string, StringPattern>[] GetPatterns();
}
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
AnyOf<string, StringPattern>[] GetPatterns();
/// <summary>
/// The <see cref="Matchers.MatchOperator"/>.
/// </summary>
MatchOperator MatchOperator { get; }
}

View File

@@ -1,15 +1,14 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IValueMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public interface IValueMatcher : IObjectMatcher
{
/// <summary>
/// IValueMatcher
/// Gets the value (can be a string or an object).
/// </summary>
/// <seealso cref="IObjectMatcher" />
public interface IValueMatcher : IObjectMatcher
{
/// <summary>
/// Gets the value (can be a string or an object).
/// </summary>
/// <returns>Value</returns>
object Value { get; }
}
/// <returns>Value</returns>
object Value { get; }
}

View File

@@ -1,121 +1,126 @@
using System.Linq;
using AnyOfTypes;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using Stef.Validation;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// JsonPathMatcher
/// </summary>
/// <seealso cref="IMatcher" />
/// <seealso cref="IObjectMatcher" />
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// JsonPathMatcher
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <seealso cref="IMatcher" />
/// <seealso cref="IObjectMatcher" />
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns())
{
private readonly AnyOf<string, StringPattern>[] _patterns;
}
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
{
}
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(
MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns)
{
_patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator;
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns.ToAnyOfPatterns())
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher([NotNull] params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf<string, StringPattern>[] patterns)
{
Guard.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
double match = MatchScores.Mismatch;
if (input != null)
try
{
try
var jToken = JToken.Parse(input);
match = IsMatch(jToken);
}
catch (JsonException)
{
if (ThrowException)
{
var jToken = JToken.Parse(input);
match = IsMatch(jToken);
}
catch (JsonException)
{
if (ThrowException)
{
throw;
}
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
double match = MatchScores.Mismatch;
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
{
try
{
try
// Check if JToken or object
JToken jToken = input as JToken ?? JObject.FromObject(input);
match = IsMatch(jToken);
}
catch (JsonException)
{
if (ThrowException)
{
// Check if JToken or object
JToken jToken = input is JToken token ? token : JObject.FromObject(input);
match = IsMatch(jToken);
}
catch (JsonException)
{
if (ThrowException)
{
throw;
}
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonPathMatcher";
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
private double IsMatch(JToken jToken)
{
return MatchScores.ToScore(_patterns.Select(pattern => jToken.SelectToken(pattern.GetPattern()) != null));
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonPathMatcher";
private double IsMatch(JToken jToken)
{
return MatchScores.ToScore(_patterns.Select(pattern => jToken.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator);
}
}

View File

@@ -1,111 +1,119 @@
using System.Linq;
using AnyOfTypes;
using DevLab.JmesPath;
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Linq;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using Stef.Validation;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// http://jmespath.org/
/// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// http://jmespath.org/
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns())
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns.ToAnyOfPatterns())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher([NotNull] params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(bool throwException = false, [NotNull] params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, throwException, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf<string, StringPattern>[] patterns)
{
Guard.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
try
{
match = MatchScores.ToScore(_patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))));
}
catch (JsonException)
{
if (ThrowException)
{
throw;
}
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
double match = MatchScores.Mismatch;
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
{
string inputAsString = JsonConvert.SerializeObject(input);
return IsMatch(inputAsString);
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher";
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(bool throwException = false, MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns) :
this(MatchBehaviour.AcceptOnMatch, throwException, matchOperator, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(
MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns)
{
_patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
try
{
var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray();
match = MatchScores.ToScore(results, MatchOperator);
}
catch (JsonException)
{
if (ThrowException)
{
throw;
}
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
// When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[]))
{
string inputAsString = JsonConvert.SerializeObject(input);
return IsMatch(inputAsString);
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher";
}

View File

@@ -6,164 +6,161 @@ using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Util;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// JsonMatcher
/// </summary>
public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{
/// <inheritdoc cref="IMatcher.Name"/>
public virtual string Name => "JsonMatcher";
/// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
public bool IgnoreCase { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly JToken _valueAsJToken;
private readonly Func<JToken, JToken> _jTokenConverter;
/// <summary>
/// JsonMatcher
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
/// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; }
}
/// <inheritdoc cref="IMatcher.Name"/>
public virtual string Name => "JsonMatcher";
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
}
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
{
Guard.NotNull(value, nameof(value));
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
public bool IgnoreCase { get; }
MatchBehaviour = matchBehaviour;
IgnoreCase = ignoreCase;
ThrowException = throwException;
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
Value = value;
_valueAsJToken = ConvertValueToJToken(value);
_jTokenConverter = ignoreCase ? Rename : jToken => jToken;
}
private readonly JToken _valueAsJToken;
private readonly Func<JToken, JToken> _jTokenConverter;
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object? input)
{
bool match = false;
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
// When input is null or byte[], return Mismatch.
if (input != null && input is not byte[])
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
{
Guard.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
IgnoreCase = ignoreCase;
ThrowException = throwException;
Value = value;
_valueAsJToken = ConvertValueToJToken(value);
_jTokenConverter = ignoreCase
? (Func<JToken, JToken>)Rename
: jToken => jToken;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object? input)
{
bool match = false;
// When input is null or byte[], return Mismatch.
if (input != null && input is not byte[])
try
{
try
{
var inputAsJToken = ConvertValueToJToken(input);
var inputAsJToken = ConvertValueToJToken(input);
match = IsMatch(
_jTokenConverter(_valueAsJToken),
_jTokenConverter(inputAsJToken));
}
catch (JsonException)
match = IsMatch(
_jTokenConverter(_valueAsJToken),
_jTokenConverter(inputAsJToken));
}
catch (JsonException)
{
if (ThrowException)
{
if (ThrowException)
{
throw;
}
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <summary>
/// Compares the input against the matcher value
/// </summary>
/// <param name="value">Matcher value</param>
/// <param name="input">Input value</param>
/// <returns></returns>
protected virtual bool IsMatch(JToken value, JToken input)
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <summary>
/// Compares the input against the matcher value
/// </summary>
/// <param name="value">Matcher value</param>
/// <param name="input">Input value</param>
/// <returns></returns>
protected virtual bool IsMatch(JToken value, JToken input)
{
return JToken.DeepEquals(value, input);
}
private static JToken ConvertValueToJToken(object value)
{
// Check if JToken, string, IEnumerable or object
switch (value)
{
return JToken.DeepEquals(value, input);
}
case JToken tokenValue:
return tokenValue;
private static JToken ConvertValueToJToken(object value)
{
// Check if JToken, string, IEnumerable or object
switch (value)
{
case JToken tokenValue:
return tokenValue;
case string stringValue:
return JsonUtils.Parse(stringValue);
case string stringValue:
return JsonUtils.Parse(stringValue);
case IEnumerable enumerableValue:
return JArray.FromObject(enumerableValue);
case IEnumerable enumerableValue:
return JArray.FromObject(enumerableValue);
default:
return JObject.FromObject(value);
}
}
private static string? ToUpper(string? input)
{
return input?.ToUpperInvariant();
}
// https://stackoverflow.com/questions/11679804/json-net-rename-properties
private static JToken Rename(JToken json)
{
if (json is JProperty property)
{
JToken propertyValue = property.Value;
if (propertyValue.Type == JTokenType.String)
{
string stringValue = propertyValue.Value<string>();
propertyValue = ToUpper(stringValue);
}
return new JProperty(ToUpper(property.Name), Rename(propertyValue));
}
if (json is JArray array)
{
var renamedValues = array.Select(Rename);
return new JArray(renamedValues);
}
if (json is JObject obj)
{
var renamedProperties = obj.Properties().Select(Rename);
return new JObject(renamedProperties);
}
return json;
default:
return JObject.FromObject(value);
}
}
private static string? ToUpper(string? input)
{
return input?.ToUpperInvariant();
}
// https://stackoverflow.com/questions/11679804/json-net-rename-properties
private static JToken Rename(JToken json)
{
if (json is JProperty property)
{
JToken propertyValue = property.Value;
if (propertyValue.Type == JTokenType.String)
{
string stringValue = propertyValue.Value<string>()!;
propertyValue = ToUpper(stringValue);
}
return new JProperty(ToUpper(property.Name)!, Rename(propertyValue));
}
if (json is JArray array)
{
var renamedValues = array.Select(Rename);
return new JArray(renamedValues);
}
if (json is JObject obj)
{
var renamedProperties = obj.Properties().Select(Rename);
return new JObject(renamedProperties);
}
return json;
}
}

View File

@@ -1,38 +1,35 @@
using JetBrains.Annotations;
namespace WireMock.Matchers;
namespace WireMock.Matchers
/// <summary>
/// JsonPartialMatcher
/// </summary>
public class JsonPartialMatcher : AbstractJsonPartialMatcher
{
/// <summary>
/// JsonPartialMatcher
/// </summary>
public class JsonPartialMatcher : AbstractJsonPartialMatcher
/// <inheritdoc />
public override string Name => nameof(JsonPartialMatcher);
/// <inheritdoc />
public JsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException, regex)
{
/// <inheritdoc />
public override string Name => nameof(JsonPartialMatcher);
/// <inheritdoc />
public JsonPartialMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <inheritdoc />
public JsonPartialMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
{
}
/// <inheritdoc />
public JsonPartialMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
: base(matchBehaviour, value, ignoreCase, throwException)
{
}
/// <inheritdoc />
protected override bool IsMatch(string value, string input)
{
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, ThrowException, value);
return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input));
}
}
}
/// <inheritdoc />
public JsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException, regex)
{
}
/// <inheritdoc />
public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException, regex)
{
}
/// <inheritdoc />
protected override bool IsMatch(string value, string input)
{
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, ThrowException, MatchOperator.Or, value);
return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input));
}
}

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