Compare commits

..

21 Commits
1.5.0 ... 1.5.4

Author SHA1 Message Date
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
219 changed files with 10569 additions and 14526 deletions

View File

@@ -1,3 +1,35 @@
# 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)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.5.0</VersionPrefix>
<VersionPrefix>1.5.4</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.5.0
SET version=1.5.4
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,4 +1,16 @@
# 1.5.0 (09 June 2022)
- #755 Add MatchOperator &quot;Or&quot;, &quot;And&quot; and &quot;Average&quot; for patterns [feature]
# 1.5.4 (24 August 2022)
- #778 Fix Proxying when StartAdminInterface=true [bug]
- #781 Update some NuGet packages [feature]
- #783 Fix WithBody when using Pact and added more nullable annotations [feature]
- #787 Add support for PEM certificates
- #789 Add support for Matcher.Pattern in Pact Body mapping [feature]
- #790 Add Response.WithBody with IJsonConverter [feature]
- #795 Add check for duplicate Guids when posting multiple mappings in one request
- #797 Fix WithHeader when using RejectOnMatch [bug]
- #775 When &quot;StartAdminInterface&quot; is true then each time is generated new mapping from the proxy [bug]
- #784 Response body is missing in generated pact file when IBodyResponseBuilder.WithBody is used [bug]
- #785 Support for PEM certificates when using ssl [feature]
- #788 Request body is missing in generated pact file for requests that include matching on request body [bug]
- #796 RequestMessageHeaderMatcher with MatchBehaviour.RejectOnMatch reverses match results twice [bug]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -103,6 +103,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Proxy.
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
@@ -245,6 +247,10 @@ Global
{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
@@ -286,6 +292,7 @@ Global
{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,6 +28,7 @@
<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/=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

@@ -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

@@ -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,48 +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>
/// 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,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,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(IRequestMessage requestMessage, 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

@@ -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

@@ -59,7 +59,7 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
MatchOperator = matchOperator;
}
public double IsMatch(string input)
public double IsMatch(string? input)
{
return IsMatchInternal(input);
}

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

@@ -1,4 +1,5 @@
#if !NETSTANDARD1_3
using System;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Text.RegularExpressions;
@@ -6,67 +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 MatchOperator MatchOperator { get; } = MatchOperator.Or;
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

@@ -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,73 @@ 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, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
{
Guard.NotNull(client);
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(HttpClient client, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
{
Guard.NotNull(client);
Guard.NotNull(request);
Guard.NotNull(originalRequestMessage);
Guard.NotNull(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(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

@@ -20,22 +20,22 @@ public interface IMapping
/// <summary>
/// Gets the TimeSettings (Start, End and TTL).
/// </summary>
ITimeSettings TimeSettings { get; }
ITimeSettings? TimeSettings { get; }
/// <summary>
/// Gets the unique title.
/// </summary>
string Title { get; }
string? Title { get; }
/// <summary>
/// Gets the description.
/// </summary>
string Description { get; }
string? Description { get; }
/// <summary>
/// The full filename path for this mapping (only defined for static mappings).
/// </summary>
string Path { get; set; }
string? Path { get; set; }
/// <summary>
/// Gets the priority. (A low value means higher priority.)
@@ -117,7 +117,7 @@ public interface IMapping
/// </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);
Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
/// <summary>
/// Gets the RequestMatchResult based on the RequestMessage.

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,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; }
/// <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 || 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)
{
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;
}
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 cref="IMapping.ProvideResponseAsync" />
public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
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)
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState)
{
var result = new RequestMatchResult();
RequestMatcher.GetMatchingScore(requestMessage, result);
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;
// 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;
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using WireMock.Util;
namespace WireMock.Matchers;
@@ -9,15 +10,22 @@ namespace WireMock.Matchers;
/// </summary>
public abstract class AbstractJsonPartialMatcher : JsonMatcher
{
/// <summary>
/// Support Regex
/// </summary>
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>
protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false)
/// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException)
{
Regex = regex;
}
/// <summary>
@@ -26,9 +34,11 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
/// <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(object value, bool ignoreCase = false, bool throwException = false)
/// <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>
@@ -38,9 +48,11 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
/// <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, object value, bool ignoreCase = false, bool throwException = false)
/// <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 />
@@ -51,6 +63,17 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
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;

View File

@@ -18,7 +18,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// </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)
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{
}
@@ -28,7 +28,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{
}
@@ -57,7 +57,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <inheritdoc cref="RegexMatcher.IsMatch"/>
public override double IsMatch(string? input)
{
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
}

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,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

@@ -6,115 +6,114 @@ using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
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(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns())
{
}
/// <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";
}
/// <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

@@ -13,12 +13,12 @@ namespace WireMock.Matchers;
/// </summary>
public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{
/// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; }
/// <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; }
@@ -68,9 +68,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
Value = value;
_valueAsJToken = ConvertValueToJToken(value);
_jTokenConverter = ignoreCase
? (Func<JToken, JToken>)Rename
: jToken => jToken;
_jTokenConverter = ignoreCase ? Rename : jToken => jToken;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
@@ -121,7 +119,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
return tokenValue;
case string stringValue:
return JsonUtils.Parse(stringValue)!;
return JsonUtils.Parse(stringValue);
case IEnumerable enumerableValue:
return JArray.FromObject(enumerableValue);

View File

@@ -9,20 +9,20 @@ public class JsonPartialMatcher : AbstractJsonPartialMatcher
public override string Name => nameof(JsonPartialMatcher);
/// <inheritdoc />
public JsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
public JsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException, regex)
{
}
/// <inheritdoc />
public JsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
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)
: base(matchBehaviour, value, ignoreCase, throwException)
public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException, regex)
{
}

View File

@@ -1,5 +1,3 @@
using JetBrains.Annotations;
namespace WireMock.Matchers;
/// <summary>
@@ -11,20 +9,20 @@ public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
public override string Name => nameof(JsonPartialWildcardMatcher);
/// <inheritdoc />
public JsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
public JsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException, regex)
{
}
/// <inheritdoc />
public JsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool throwException = false)
: base(value, ignoreCase, throwException)
public JsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(value, ignoreCase, throwException, regex)
{
}
/// <inheritdoc />
public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
: base(matchBehaviour, value, ignoreCase, throwException)
public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException, regex)
{
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using AnyOfTypes;
@@ -68,7 +69,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
@@ -94,7 +95,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
@@ -105,9 +106,12 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
value = valueAsJObject;
break;
default:
value = JObject.FromObject(input);
case { } valueAsObject:
value = JObject.FromObject(valueAsObject);
break;
default:
return MatchScores.Mismatch;
}
// Convert a single object to a Queryable JObject-list with 1 entry.

View File

@@ -1,18 +1,17 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// MatchBehaviour
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// MatchBehaviour
/// Accept on match (default)
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// Accept on match (default)
/// </summary>
AcceptOnMatch,
AcceptOnMatch,
/// <summary>
/// Reject on match
/// </summary>
RejectOnMatch
}
/// <summary>
/// Reject on match
/// </summary>
RejectOnMatch
}

View File

@@ -1,27 +1,26 @@
namespace WireMock.Matchers
{
internal static class MatchBehaviourHelper
{
/// <summary>
/// Converts the specified match behaviour and match value to a new match value.
///
/// if AcceptOnMatch --> return match (default)
/// if RejectOnMatch and match = 0.0 --> return 1.0
/// if RejectOnMatch and match = 0.? --> return 0.0
/// if RejectOnMatch and match = 1.0 --> return 0.0
/// </summary>
///
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="match">The match.</param>
/// <returns>match value</returns>
internal static double Convert(MatchBehaviour matchBehaviour, double match)
{
if (matchBehaviour == MatchBehaviour.AcceptOnMatch)
{
return match;
}
namespace WireMock.Matchers;
return match <= MatchScores.Tolerance ? MatchScores.Perfect : MatchScores.Mismatch;
internal static class MatchBehaviourHelper
{
/// <summary>
/// Converts the specified match behaviour and match value to a new match value.
///
/// if AcceptOnMatch --> return match (default)
/// if RejectOnMatch and match = 0.0 --> return 1.0
/// if RejectOnMatch and match = 0.? --> return 0.0
/// if RejectOnMatch and match = 1.0 --> return 0.0
/// </summary>
///
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="match">The match.</param>
/// <returns>match value</returns>
internal static double Convert(MatchBehaviour matchBehaviour, double match)
{
if (matchBehaviour == MatchBehaviour.AcceptOnMatch)
{
return match;
}
return match <= MatchScores.Tolerance ? MatchScores.Perfect : MatchScores.Mismatch;
}
}

View File

@@ -1,18 +1,17 @@
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// CompositeMatcherType
/// </summary>
public enum CompositeMatcherType
{
/// <summary>
/// CompositeMatcherType
/// And
/// </summary>
public enum CompositeMatcherType
{
/// <summary>
/// And
/// </summary>
And = 0,
And = 0,
/// <summary>
/// Or
/// </summary>
Or = 1
}
/// <summary>
/// Or
/// </summary>
Or = 1
}

View File

@@ -1,57 +1,56 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// RequestMatchResult
/// </summary>
public class RequestMatchResult : IRequestMatchResult
{
/// <inheritdoc cref="IRequestMatchResult.TotalScore" />
public double TotalScore => MatchDetails.Sum(md => md.Score);
/// <inheritdoc cref="IRequestMatchResult.TotalNumber" />
public int TotalNumber => MatchDetails.Count;
/// <inheritdoc cref="IRequestMatchResult.IsPerfectMatch" />
public bool IsPerfectMatch => Math.Abs(TotalScore - TotalNumber) < MatchScores.Tolerance;
/// <inheritdoc cref="IRequestMatchResult.AverageTotalScore" />
public double AverageTotalScore => TotalNumber == 0 ? 0.0 : TotalScore / TotalNumber;
/// <inheritdoc cref="IRequestMatchResult.MatchDetails" />
public IList<MatchDetail> MatchDetails { get; } = new List<MatchDetail>();
/// <summary>
/// RequestMatchResult
/// Adds the score.
/// </summary>
public class RequestMatchResult : IRequestMatchResult
/// <param name="matcherType">The matcher Type.</param>
/// <param name="score">The score.</param>
/// <returns>The score.</returns>
public double AddScore(Type matcherType, double score)
{
/// <inheritdoc cref="IRequestMatchResult.TotalScore" />
public double TotalScore => MatchDetails.Sum(md => md.Score);
MatchDetails.Add(new MatchDetail { MatcherType = matcherType, Score = score });
/// <inheritdoc cref="IRequestMatchResult.TotalNumber" />
public int TotalNumber => MatchDetails.Count;
return score;
}
/// <inheritdoc cref="IRequestMatchResult.IsPerfectMatch" />
public bool IsPerfectMatch => Math.Abs(TotalScore - TotalNumber) < MatchScores.Tolerance;
/// <summary>
/// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes <paramref name="obj" /> in the sort order. Zero This instance occurs in the same position in the sort order as <paramref name="obj" />. Greater than zero This instance follows <paramref name="obj" /> in the sort order.
/// </returns>
public int CompareTo(object obj)
{
var compareObj = (RequestMatchResult)obj;
/// <inheritdoc cref="IRequestMatchResult.AverageTotalScore" />
public double AverageTotalScore => TotalNumber == 0 ? 0.0 : TotalScore / TotalNumber;
int averageTotalScoreResult = compareObj.AverageTotalScore.CompareTo(AverageTotalScore);
/// <inheritdoc cref="IRequestMatchResult.MatchDetails" />
public IList<MatchDetail> MatchDetails { get; } = new List<MatchDetail>();
/// <summary>
/// Adds the score.
/// </summary>
/// <param name="matcherType">The matcher Type.</param>
/// <param name="score">The score.</param>
/// <returns>The score.</returns>
public double AddScore(Type matcherType, double score)
{
MatchDetails.Add(new MatchDetail { MatcherType = matcherType, Score = score });
return score;
}
/// <summary>
/// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes <paramref name="obj" /> in the sort order. Zero This instance occurs in the same position in the sort order as <paramref name="obj" />. Greater than zero This instance follows <paramref name="obj" /> in the sort order.
/// </returns>
public int CompareTo(object obj)
{
var compareObj = (RequestMatchResult)obj;
int averageTotalScoreResult = compareObj.AverageTotalScore.CompareTo(AverageTotalScore);
// In case the score is equal, prefer the one with the most matchers.
return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult;
}
// In case the score is equal, prefer the one with the most matchers.
return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult;
}
}

View File

@@ -3,50 +3,49 @@ using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The composite request matcher.
/// </summary>
public abstract class RequestMessageCompositeMatcher : IRequestMatcher
{
private readonly CompositeMatcherType _type;
/// <summary>
/// The composite request matcher.
/// Gets the request matchers.
/// </summary>
public abstract class RequestMessageCompositeMatcher : IRequestMatcher
/// <value>
/// The request matchers.
/// </value>
private IEnumerable<IRequestMatcher> RequestMatchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class.
/// </summary>
/// <param name="requestMatchers">The request matchers.</param>
/// <param name="type">The CompositeMatcherType type (Defaults to 'And')</param>
protected RequestMessageCompositeMatcher([NotNull] IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
{
private readonly CompositeMatcherType _type;
Guard.NotNull(requestMatchers, nameof(requestMatchers));
/// <summary>
/// Gets the request matchers.
/// </summary>
/// <value>
/// The request matchers.
/// </value>
private IEnumerable<IRequestMatcher> RequestMatchers { get; }
_type = type;
RequestMatchers = requestMatchers;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class.
/// </summary>
/// <param name="requestMatchers">The request matchers.</param>
/// <param name="type">The CompositeMatcherType type (Defaults to 'And')</param>
protected RequestMessageCompositeMatcher([NotNull] IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
if (!RequestMatchers.Any())
{
Guard.NotNull(requestMatchers, nameof(requestMatchers));
_type = type;
RequestMatchers = requestMatchers;
return MatchScores.Mismatch;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
if (_type == CompositeMatcherType.And)
{
if (!RequestMatchers.Any())
{
return MatchScores.Mismatch;
}
if (_type == CompositeMatcherType.And)
{
return RequestMatchers.Average(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
}
return RequestMatchers.Max(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
return RequestMatchers.Average(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
}
return RequestMatchers.Max(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
}
}

View File

@@ -4,126 +4,125 @@ using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request cookie matcher.
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageCookieMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
/// <summary>
/// The request cookie matcher.
/// The functions
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageCookieMatcher : IRequestMatcher
public Func<IDictionary<string, string>, bool>[] Funcs { get; }
/// <summary>
/// The name
/// </summary>
public string Name { get; }
/// <value>
/// The matchers.
/// </value>
public IStringMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, [NotNull] string pattern, bool ignoreCase)
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
Guard.NotNull(name, nameof(name));
Guard.NotNull(pattern, nameof(pattern));
/// <summary>
/// The functions
/// </summary>
public Func<IDictionary<string, string>, bool>[] Funcs { get; }
_matchBehaviour = matchBehaviour;
_ignoreCase = ignoreCase;
Name = name;
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) };
}
/// <summary>
/// The name
/// </summary>
public string Name { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params string[] patterns) :
this(matchBehaviour, name, ignoreCase, patterns.Select(pattern => new WildcardMatcher(matchBehaviour, pattern, ignoreCase)).Cast<IStringMatcher>().ToArray())
{
Guard.NotNull(patterns, nameof(patterns));
}
/// <value>
/// The matchers.
/// </value>
public IStringMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params IStringMatcher[] matchers)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(matchers, nameof(matchers));
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, [NotNull] string pattern, bool ignoreCase)
_matchBehaviour = matchBehaviour;
Name = name;
Matchers = matchers;
_ignoreCase = ignoreCase;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageCookieMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Cookies == null)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(pattern, nameof(pattern));
_matchBehaviour = matchBehaviour;
_ignoreCase = ignoreCase;
Name = name;
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) };
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params string[] patterns) :
this(matchBehaviour, name, ignoreCase, patterns.Select(pattern => new WildcardMatcher(matchBehaviour, pattern, ignoreCase)).Cast<IStringMatcher>().ToArray())
// Check if we want to use IgnoreCase to compare the Cookie-Name and Cookie-Value
var cookies = !_ignoreCase ? requestMessage.Cookies : new Dictionary<string, string>(requestMessage.Cookies, StringComparer.OrdinalIgnoreCase);
if (Funcs != null)
{
Guard.NotNull(patterns, nameof(patterns));
return MatchScores.ToScore(Funcs.Any(f => f(cookies)));
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params IStringMatcher[] matchers)
if (Matchers == null)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(matchers, nameof(matchers));
_matchBehaviour = matchBehaviour;
Name = name;
Matchers = matchers;
_ignoreCase = ignoreCase;
return MatchScores.Mismatch;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageCookieMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
if (!cookies.ContainsKey(Name))
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Cookies == null)
{
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
// Check if we want to use IgnoreCase to compare the Cookie-Name and Cookie-Value
var cookies = !_ignoreCase ? requestMessage.Cookies : new Dictionary<string, string>(requestMessage.Cookies, StringComparer.OrdinalIgnoreCase);
if (Funcs != null)
{
return MatchScores.ToScore(Funcs.Any(f => f(cookies)));
}
if (Matchers == null)
{
return MatchScores.Mismatch;
}
if (!cookies.ContainsKey(Name))
{
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
string value = cookies[Name];
return Matchers.Max(m => m.IsMatch(value));
}
string value = cookies[Name];
return Matchers.Max(m => m.IsMatch(value));
}
}

View File

@@ -23,7 +23,7 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
/// <summary>
/// The name
/// </summary>
public string? Name { get; }
public string Name { get; }
/// <value>
/// The matchers.
@@ -94,6 +94,7 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
public RequestMessageHeaderMatcher(params Func<IDictionary<string, string[]>, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
Name = string.Empty; // Not used when Func, but set to a non-null valid value.
}
/// <inheritdoc />
@@ -121,7 +122,7 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
if (Matchers != null)
{
if (!headers.ContainsKey(Name!))
if (!headers.ContainsKey(Name))
{
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
@@ -129,12 +130,12 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
var results = new List<double>();
foreach (var matcher in Matchers)
{
var resultsPerMatcher = headers[Name!].Select(v => matcher.IsMatch(v)).ToArray();
var resultsPerMatcher = headers[Name].Select(v => matcher.IsMatch(v)).ToArray();
results.Add(MatchScores.ToScore(resultsPerMatcher, MatchOperator.And));
}
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.ToScore(results, MatchOperator));
return MatchScores.ToScore(results, MatchOperator);
}
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);

View File

@@ -92,7 +92,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
WireMockList<string> valuesPresentInRequestMessage = ((RequestMessage)requestMessage).GetParameter(Key, IgnoreCase ?? false);
var valuesPresentInRequestMessage = ((RequestMessage)requestMessage).GetParameter(Key!, IgnoreCase ?? false);
if (valuesPresentInRequestMessage == null)
{
// Key is not present at all, just return Mismatch
@@ -102,7 +102,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
if (Matchers != null && Matchers.Any())
{
// Return the score based on Matchers and valuesPresentInRequestMessage
return CalculateScore(valuesPresentInRequestMessage);
return CalculateScore(Matchers, valuesPresentInRequestMessage);
}
if (Matchers == null || !Matchers.Any())
@@ -114,14 +114,14 @@ public class RequestMessageParamMatcher : IRequestMatcher
return MatchScores.Mismatch;
}
private double CalculateScore(WireMockList<string> valuesPresentInRequestMessage)
private double CalculateScore(IReadOnlyList<IStringMatcher> matchers, WireMockList<string> valuesPresentInRequestMessage)
{
var total = new List<double>();
// If the total patterns in all matchers > values in message, use the matcher as base
if (Matchers.Sum(m => m.GetPatterns().Length) > valuesPresentInRequestMessage.Count)
if (matchers.Sum(m => m.GetPatterns().Length) > valuesPresentInRequestMessage.Count)
{
foreach (var matcher in Matchers)
foreach (var matcher in matchers)
{
double score = 0d;
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
@@ -136,7 +136,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
{
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{
double score = Matchers.Max(m => m.IsMatch(valuePresentInRequestMessage));
double score = matchers.Max(m => m.IsMatch(valuePresentInRequestMessage));
total.Add(score);
}
}

View File

@@ -1,46 +1,41 @@
using JetBrains.Annotations;
namespace WireMock.Matchers.Request;
namespace WireMock.Matchers.Request
/// <summary>
/// The scenario and state matcher.
/// </summary>
internal class RequestMessageScenarioAndStateMatcher : IRequestMatcher
{
/// <summary>
/// The scenario and state matcher.
/// Execution state condition for the current mapping.
/// </summary>
internal class RequestMessageScenarioAndStateMatcher : IRequestMatcher
private readonly string? _executionConditionState;
/// <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>
private readonly string? _nextState;
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageScenarioAndStateMatcher"/> class.
/// </summary>
/// <param name="nextState">The next state.</param>
/// <param name="executionConditionState">Execution state condition for the current mapping.</param>
public RequestMessageScenarioAndStateMatcher(string? nextState, string? executionConditionState)
{
/// <summary>
/// Execution state condition for the current mapping.
/// </summary>
[CanBeNull]
private readonly string _executionConditionState;
_nextState = nextState;
_executionConditionState = executionConditionState;
}
/// <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]
private readonly string _nextState;
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch();
return requestMatchResult.AddScore(GetType(), score);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageScenarioAndStateMatcher"/> class.
/// </summary>
/// <param name="nextState">The next state.</param>
/// <param name="executionConditionState">Execution state condition for the current mapping.</param>
public RequestMessageScenarioAndStateMatcher([CanBeNull] string nextState, [CanBeNull] string executionConditionState)
{
_nextState = nextState;
_executionConditionState = executionConditionState;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch();
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch()
{
return Equals(_executionConditionState, _nextState) ? MatchScores.Perfect : MatchScores.Mismatch;
}
private double IsMatch()
{
return Equals(_executionConditionState, _nextState) ? MatchScores.Perfect : MatchScores.Mismatch;
}
}

View File

@@ -3,45 +3,44 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
namespace WireMock.Owin
namespace WireMock.Owin;
internal partial class AspNetCoreSelfHost
{
internal partial class AspNetCoreSelfHost
public void AddCors(IServiceCollection services)
{
public void AddCors(IServiceCollection services)
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
services.AddCors(corsOptions => corsOptions
.AddPolicy(CorsPolicyName,
corsPolicyBuilder =>
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
services.AddCors(corsOptions => corsOptions
.AddPolicy(CorsPolicyName,
corsPolicyBuilder =>
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyHeader))
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyHeader))
{
corsPolicyBuilder.AllowAnyHeader();
}
corsPolicyBuilder.AllowAnyHeader();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyMethod))
{
corsPolicyBuilder.AllowAnyMethod();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyMethod))
{
corsPolicyBuilder.AllowAnyMethod();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyOrigin))
{
corsPolicyBuilder.AllowAnyOrigin();
}
}));
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyOrigin))
{
corsPolicyBuilder.AllowAnyOrigin();
}
}));
}
}
public void UseCors(IApplicationBuilder appBuilder)
public void UseCors(IApplicationBuilder appBuilder)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* Use Cors */
appBuilder.UseCors(CorsPolicyName);
}
/* Use Cors */
appBuilder.UseCors(CorsPolicyName);
}
}
}

View File

@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate;
using WireMock.Types;
namespace WireMock.Owin
{

View File

@@ -1,4 +1,4 @@
#if USE_ASPNETCORE && NETSTANDARD1_3
#if USE_ASPNETCORE && NETSTANDARD1_3
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel;
@@ -6,58 +6,58 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate;
namespace WireMock.Owin
{
internal partial class AspNetCoreSelfHost
{
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
{
options.Limits.MaxRequestBufferSize = null;
options.Limits.MaxRequestHeaderCount = 100;
options.Limits.MaxResponseBufferSize = null;
}
namespace WireMock.Owin;
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
internal partial class AspNetCoreSelfHost
{
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
{
options.Limits.MaxRequestBufferSize = null;
options.Limits.MaxRequestHeaderCount = 100;
options.Limits.MaxResponseBufferSize = null;
}
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
{
foreach (var urlDetail in urlDetails)
{
foreach (var urlDetail in urlDetails)
if (urlDetail.IsHttps)
{
if (urlDetail.IsHttps)
if (wireMockMiddlewareOptions.CustomCertificateDefined)
{
if (wireMockMiddlewareOptions.CustomCertificateDefined)
{
options.UseHttps(CertificateLoader.LoadCertificate(
wireMockMiddlewareOptions.X509StoreName,
wireMockMiddlewareOptions.X509StoreLocation,
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
wireMockMiddlewareOptions.X509CertificateFilePath,
wireMockMiddlewareOptions.X509CertificatePassword,
urlDetail.Host)
);
}
else
{
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
}
options.UseHttps(CertificateLoader.LoadCertificate(
wireMockMiddlewareOptions.X509StoreName,
wireMockMiddlewareOptions.X509StoreLocation,
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
wireMockMiddlewareOptions.X509CertificateFilePath,
wireMockMiddlewareOptions.X509CertificatePassword,
urlDetail.Host)
);
}
else
{
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
}
}
}
}
}
internal static class IWebHostBuilderExtensions
internal static class IWebHostBuilderExtensions
{
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
{
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
return builder.ConfigureServices(services =>
{
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
return builder.ConfigureServices(services =>
{
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
});
}
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
});
}
}
#endif

View File

@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
@@ -30,16 +29,16 @@ namespace WireMock.Owin
public bool IsStarted { get; private set; }
public List<string> Urls { get; } = new List<string>();
public List<string> Urls { get; } = new();
public List<int> Ports { get; } = new List<int>();
public List<int> Ports { get; } = new();
public Exception RunningException => _runningException;
public AspNetCoreSelfHost([NotNull] IWireMockMiddlewareOptions wireMockMiddlewareOptions, [NotNull] HostUrlOptions urlOptions)
public AspNetCoreSelfHost(IWireMockMiddlewareOptions wireMockMiddlewareOptions, HostUrlOptions urlOptions)
{
Guard.NotNull(wireMockMiddlewareOptions, nameof(wireMockMiddlewareOptions));
Guard.NotNull(urlOptions, nameof(urlOptions));
Guard.NotNull(wireMockMiddlewareOptions);
Guard.NotNull(urlOptions);
_logger = wireMockMiddlewareOptions.Logger ?? new WireMockConsoleLogger();
@@ -119,7 +118,7 @@ namespace WireMock.Owin
{
Urls.Add(address.Replace("0.0.0.0", "localhost").Replace("[::]", "localhost"));
PortUtils.TryExtract(address, out bool isHttps, out string protocol, out string host, out int port);
PortUtils.TryExtract(address, out _, out _, out _, out int port);
Ports.Add(port);
}
@@ -133,7 +132,7 @@ namespace WireMock.Owin
#elif NETSTANDARD2_1
_logger.Info("Server using netstandard2.1");
#elif NETCOREAPP3_1
_logger.Info("Server using .NET Core 3.1");
_logger.Info("Server using .NET Core App 3.1");
#elif NET5_0
_logger.Info("Server using .NET 5.0");
#elif NET6_0

View File

@@ -1,15 +1,14 @@
namespace WireMock.Owin
namespace WireMock.Owin;
internal struct HostUrlDetails
{
internal class HostUrlDetails
{
public bool IsHttps { get; set; }
public bool IsHttps { get; set; }
public string Url { get; set; }
public string Url { get; set; }
public string Protocol { get; set; }
public string Protocol { get; set; }
public string Host { get; set; }
public string Host { get; set; }
public int Port { get; set; }
}
public int Port { get; set; }
}

View File

@@ -1,46 +1,47 @@
using System.Collections.Generic;
using System.Collections.Generic;
using WireMock.Util;
namespace WireMock.Owin
namespace WireMock.Owin;
internal class HostUrlOptions
{
internal class HostUrlOptions
private const string LOCALHOST = "localhost";
public ICollection<string>? Urls { get; set; }
public int? Port { get; set; }
public bool UseSSL { get; set; }
public ICollection<HostUrlDetails> GetDetails()
{
private const string LOCALHOST = "localhost";
public ICollection<string> Urls { get; set; }
public int? Port { get; set; }
public bool UseSSL { get; set; }
public ICollection<HostUrlDetails> GetDetails()
var list = new List<HostUrlDetails>();
if (Urls == null)
{
var list = new List<HostUrlDetails>();
if (Urls == null)
int port = Port > 0 ? Port.Value : FindFreeTcpPort();
string protocol = UseSSL ? "https" : "http";
list.Add(new HostUrlDetails { IsHttps = UseSSL, Url = $"{protocol}://{LOCALHOST}:{port}", Protocol = protocol, Host = LOCALHOST, Port = port });
}
else
{
foreach (string url in Urls)
{
int port = Port > 0 ? Port.Value : FindFreeTcpPort();
string protocol = UseSSL ? "https" : "http";
list.Add(new HostUrlDetails { IsHttps = UseSSL, Url = $"{protocol}://{LOCALHOST}:{port}", Protocol = protocol, Host = LOCALHOST, Port = port });
}
else
{
foreach (string url in Urls)
if (PortUtils.TryExtract(url, out bool isHttps, out var protocol, out var host, out int port))
{
PortUtils.TryExtract(url, out bool isHttps, out string protocol, out string host, out int port);
list.Add(new HostUrlDetails { IsHttps = isHttps, Url = url, Protocol = protocol, Host = host, Port = port });
}
}
return list;
}
private int FindFreeTcpPort()
{
return list;
}
private static int FindFreeTcpPort()
{
#if USE_ASPNETCORE || NETSTANDARD2_0 || NETSTANDARD2_1
return 0;
return 0;
#else
return PortUtils.FindFreeTcpPort();
return PortUtils.FindFreeTcpPort();
#endif
}
}
}

View File

@@ -1,7 +1,6 @@
namespace WireMock.Owin
namespace WireMock.Owin;
internal interface IMappingMatcher
{
internal interface IMappingMatcher
{
(MappingMatcherResult Match, MappingMatcherResult Partial) FindBestMatch(RequestMessage request);
}
(MappingMatcherResult? Match, MappingMatcherResult? Partial) FindBestMatch(RequestMessage request);
}

View File

@@ -1,36 +1,35 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using System;
namespace WireMock.Owin
namespace WireMock.Owin;
interface IOwinSelfHost
{
interface IOwinSelfHost
{
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
/// <value>
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
/// </value>
bool IsStarted { get; }
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
/// <value>
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
/// </value>
bool IsStarted { get; }
/// <summary>
/// Gets the urls.
/// </summary>
List<string> Urls { get; }
/// <summary>
/// Gets the urls.
/// </summary>
List<string> Urls { get; }
/// <summary>
/// Gets the ports.
/// </summary>
List<int> Ports { get; }
/// <summary>
/// Gets the ports.
/// </summary>
List<int> Ports { get; }
/// <summary>
/// The exception occurred when the host is running
/// </summary>
Exception RunningException { get; }
/// <summary>
/// The exception occurred when the host is running.
/// </summary>
Exception? RunningException { get; }
Task StartAsync();
Task StartAsync();
Task StopAsync();
}
Task StopAsync();
}

View File

@@ -12,62 +12,61 @@ using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
using Microsoft.Extensions.DependencyInjection;
#endif
namespace WireMock.Owin
namespace WireMock.Owin;
internal interface IWireMockMiddlewareOptions
{
internal interface IWireMockMiddlewareOptions
{
IWireMockLogger Logger { get; set; }
IWireMockLogger Logger { get; set; }
TimeSpan? RequestProcessingDelay { get; set; }
TimeSpan? RequestProcessingDelay { get; set; }
IStringMatcher? AuthenticationMatcher { get; set; }
IStringMatcher? AuthenticationMatcher { get; set; }
bool? AllowPartialMapping { get; set; }
bool? AllowPartialMapping { get; set; }
ConcurrentDictionary<Guid, IMapping> Mappings { get; }
ConcurrentDictionary<Guid, IMapping> Mappings { get; }
ConcurrentDictionary<string, ScenarioState> Scenarios { get; }
ConcurrentDictionary<string, ScenarioState> Scenarios { get; }
ConcurrentObservableCollection<LogEntry> LogEntries { get; }
ConcurrentObservableCollection<LogEntry> LogEntries { get; }
int? RequestLogExpirationDuration { get; set; }
int? RequestLogExpirationDuration { get; set; }
int? MaxRequestLogCount { get; set; }
int? MaxRequestLogCount { get; set; }
Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
#if USE_ASPNETCORE
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
CorsPolicyOptions? CorsPolicyOptions { get; set; }
CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif
IFileSystemHandler? FileSystemHandler { get; set; }
IFileSystemHandler? FileSystemHandler { get; set; }
bool? AllowBodyForAllHttpMethods { get; set; }
bool? AllowBodyForAllHttpMethods { get; set; }
bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
bool? DisableJsonBodyParsing { get; set; }
bool? DisableJsonBodyParsing { get; set; }
bool? DisableRequestBodyDecompressing { get; set; }
bool? DisableRequestBodyDecompressing { get; set; }
bool? HandleRequestsSynchronously { get; set; }
bool? HandleRequestsSynchronously { get; set; }
string? X509StoreName { get; set; }
string? X509StoreName { get; set; }
string? X509StoreLocation { get; set; }
string? X509StoreLocation { get; set; }
string? X509ThumbprintOrSubjectName { get; set; }
string? X509ThumbprintOrSubjectName { get; set; }
string? X509CertificateFilePath { get; set; }
string? X509CertificateFilePath { get; set; }
string? X509CertificatePassword { get; set; }
string? X509CertificatePassword { get; set; }
bool CustomCertificateDefined { get; }
bool CustomCertificateDefined { get; }
bool? SaveUnmatchedRequests { get; set; }
}
bool? SaveUnmatchedRequests { get; set; }
}

View File

@@ -27,8 +27,8 @@ namespace WireMock.Owin.Mappers
string method = request.Method;
Dictionary<string, string[]> headers = null;
IEnumerable<string> contentEncodingHeader = null;
var headers = new Dictionary<string, string[]>();
IEnumerable<string>? contentEncodingHeader = null;
if (request.Headers.Any())
{
headers = new Dictionary<string, string[]>();
@@ -43,7 +43,7 @@ namespace WireMock.Owin.Mappers
}
}
IDictionary<string, string> cookies = null;
var cookies = new Dictionary<string, string>();
if (request.Cookies.Any())
{
cookies = new Dictionary<string, string>();
@@ -53,7 +53,7 @@ namespace WireMock.Owin.Mappers
}
}
IBodyData body = null;
IBodyData? body = null;
if (request.Body != null && BodyParser.ShouldParseBody(method, options.AllowBodyForAllHttpMethods == true))
{
var bodyParserSettings = new BodyParserSettings
@@ -75,13 +75,24 @@ namespace WireMock.Owin.Mappers
{
#if !USE_ASPNETCORE
var urlDetails = UrlUtils.Parse(request.Uri, request.PathBase);
string clientIP = request.RemoteIpAddress;
var clientIP = request.RemoteIpAddress;
#else
var urlDetails = UrlUtils.Parse(new Uri(request.GetEncodedUrl()), request.PathBase);
var connection = request.HttpContext.Connection;
string clientIP = connection.RemoteIpAddress.IsIPv4MappedToIPv6
? connection.RemoteIpAddress.MapToIPv4().ToString()
: connection.RemoteIpAddress.ToString();
string clientIP;
if (connection.RemoteIpAddress is null)
{
clientIP = string.Empty;
}
else if (connection.RemoteIpAddress.IsIPv4MappedToIPv6)
{
clientIP = connection.RemoteIpAddress.MapToIPv4().ToString();
}
else
{
clientIP = connection.RemoteIpAddress.ToString();
}
#endif
return (urlDetails, clientIP);
}

View File

@@ -71,7 +71,6 @@ namespace WireMock.Owin.Mappers
{
bytes = bytes.Take(bytes.Length / 2).Union(_randomizerBytes.Generate()).ToArray();
}
break;
default:
@@ -80,11 +79,10 @@ namespace WireMock.Owin.Mappers
}
var statusCodeType = responseMessage.StatusCode?.GetType();
switch (statusCodeType)
{
case Type typeAsIntOrEnum when typeAsIntOrEnum == typeof(int) || typeAsIntOrEnum == typeof(int?) || typeAsIntOrEnum.GetTypeInfo().IsEnum:
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode);
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!);
break;
case Type typeAsString when typeAsString == typeof(string):
@@ -138,7 +136,7 @@ namespace WireMock.Owin.Mappers
return responseMessage.BodyData.BodyAsBytes;
case BodyType.File:
return _options.FileSystemHandler.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
return _options.FileSystemHandler?.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
}
return null;

View File

@@ -4,72 +4,71 @@ using System.Linq;
using WireMock.Extensions;
using Stef.Validation;
namespace WireMock.Owin
namespace WireMock.Owin;
internal class MappingMatcher : IMappingMatcher
{
internal class MappingMatcher : IMappingMatcher
private readonly IWireMockMiddlewareOptions _options;
public MappingMatcher(IWireMockMiddlewareOptions options)
{
private readonly IWireMockMiddlewareOptions _options;
Guard.NotNull(options, nameof(options));
public MappingMatcher(IWireMockMiddlewareOptions options)
_options = options;
}
public (MappingMatcherResult? Match, MappingMatcherResult? Partial) FindBestMatch(RequestMessage request)
{
var possibleMappings = new List<MappingMatcherResult>();
foreach (var mapping in _options.Mappings.Values.Where(m => m.TimeSettings.IsValid()))
{
Guard.NotNull(options, nameof(options));
_options = options;
}
public (MappingMatcherResult Match, MappingMatcherResult Partial) FindBestMatch(RequestMessage request)
{
var mappings = new List<MappingMatcherResult>();
foreach (var mapping in _options.Mappings.Values.Where(m => m.TimeSettings.IsValid()))
try
{
try
var nextState = GetNextState(mapping);
possibleMappings.Add(new MappingMatcherResult
{
string nextState = GetNextState(mapping);
mappings.Add(new MappingMatcherResult
{
Mapping = mapping,
RequestMatchResult = mapping.GetRequestMatchResult(request, nextState)
});
}
catch (Exception ex)
{
_options.Logger.Error($"Getting a Request MatchResult for Mapping '{mapping.Guid}' failed. This mapping will not be evaluated. Exception: {ex}");
}
Mapping = mapping,
RequestMatchResult = mapping.GetRequestMatchResult(request, nextState)
});
}
var partialMappings = mappings
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.RequestMatchResult)
.ThenBy(m => m.Mapping.Priority)
.ToList();
var partialMatch = partialMappings.FirstOrDefault(pm => pm.RequestMatchResult.AverageTotalScore > 0.0);
if (_options.AllowPartialMapping == true)
catch (Exception ex)
{
return (partialMatch, partialMatch);
_options.Logger.Error($"Getting a Request MatchResult for Mapping '{mapping.Guid}' failed. This mapping will not be evaluated. Exception: {ex}");
}
var match = mappings
.Where(m => m.RequestMatchResult.IsPerfectMatch)
.OrderBy(m => m.Mapping.Priority).ThenBy(m => m.RequestMatchResult)
.FirstOrDefault();
return (match, partialMatch);
}
private string GetNextState(IMapping mapping)
var partialMappings = possibleMappings
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.RequestMatchResult)
.ThenBy(m => m.Mapping.Priority)
.ToList();
var partialMatch = partialMappings.FirstOrDefault(pm => pm.RequestMatchResult.AverageTotalScore > 0.0);
if (_options.AllowPartialMapping == true)
{
// If the mapping does not have a scenario or _options.Scenarios does not contain this scenario from the mapping,
// just return null to indicate that there is no next state.
if (mapping.Scenario == null || !_options.Scenarios.ContainsKey(mapping.Scenario))
{
return null;
}
// Else just return the next state
return _options.Scenarios[mapping.Scenario].NextState;
return (partialMatch, partialMatch);
}
var match = possibleMappings
.Where(m => m.RequestMatchResult.IsPerfectMatch)
.OrderBy(m => m.Mapping.Priority).ThenBy(m => m.RequestMatchResult)
.FirstOrDefault();
return (match, partialMatch);
}
private string? GetNextState(IMapping mapping)
{
// If the mapping does not have a scenario or _options.Scenarios does not contain this scenario from the mapping,
// just return null to indicate that there is no next state.
if (mapping.Scenario == null || !_options.Scenarios.ContainsKey(mapping.Scenario))
{
return null;
}
// Else just return the next state
return _options.Scenarios[mapping.Scenario].NextState;
}
}

View File

@@ -1,11 +1,10 @@
using WireMock.Matchers.Request;
namespace WireMock.Owin
{
internal class MappingMatcherResult
{
public IMapping Mapping { get; set; }
namespace WireMock.Owin;
public IRequestMatchResult RequestMatchResult { get; set; }
}
internal class MappingMatcherResult
{
public IMapping Mapping { get; set; }
public IRequestMatchResult RequestMatchResult { get; set; }
}

View File

@@ -1,110 +1,109 @@
#if !USE_ASPNETCORE
using JetBrains.Annotations;
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Logging;
using WireMock.Owin.Mappers;
using Stef.Validation;
namespace WireMock.Owin
namespace WireMock.Owin;
internal class OwinSelfHost : IOwinSelfHost
{
internal class OwinSelfHost : IOwinSelfHost
private readonly IWireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new();
private readonly IWireMockLogger _logger;
private Exception? _runningException;
public OwinSelfHost(IWireMockMiddlewareOptions options, HostUrlOptions urlOptions)
{
private readonly IWireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockLogger _logger;
Guard.NotNull(options, nameof(options));
Guard.NotNull(urlOptions, nameof(urlOptions));
private Exception _runningException;
_options = options;
_logger = options.Logger ?? new WireMockConsoleLogger();
public OwinSelfHost([NotNull] IWireMockMiddlewareOptions options, [NotNull] HostUrlOptions urlOptions)
foreach (var detail in urlOptions.GetDetails())
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(urlOptions, nameof(urlOptions));
_options = options;
_logger = options.Logger ?? new WireMockConsoleLogger();
foreach (var detail in urlOptions.GetDetails())
{
Urls.Add(detail.Url);
Ports.Add(detail.Port);
}
Urls.Add(detail.Url);
Ports.Add(detail.Port);
}
}
public bool IsStarted { get; private set; }
public bool IsStarted { get; private set; }
public List<string> Urls { get; } = new List<string>();
public List<string> Urls { get; } = new();
public List<int> Ports { get; } = new List<int>();
public List<int> Ports { get; } = new();
public Exception RunningException => _runningException;
public Exception? RunningException => _runningException;
[PublicAPI]
public Task StartAsync()
{
return Task.Run(StartServers, _cts.Token);
}
[PublicAPI]
public Task StartAsync()
{
return Task.Run(StartServers, _cts.Token);
}
[PublicAPI]
public Task StopAsync()
{
_cts.Cancel();
[PublicAPI]
public Task StopAsync()
{
_cts.Cancel();
return Task.FromResult(true);
}
return Task.FromResult(true);
}
private void StartServers()
{
private void StartServers()
{
#if NET46
_logger.Info("Server using .net 4.6.1 or higher");
_logger.Info("Server using .net 4.6.1 or higher");
#else
_logger.Info("Server using .net 4.5.x");
_logger.Info("Server using .net 4.5.x");
#endif
var servers = new List<IDisposable>();
var servers = new List<IDisposable>();
try
try
{
var requestMapper = new OwinRequestMapper();
var responseMapper = new OwinResponseMapper(_options);
var matcher = new MappingMatcher(_options);
Action<IAppBuilder> startup = app =>
{
var requestMapper = new OwinRequestMapper();
var responseMapper = new OwinResponseMapper(_options);
var matcher = new MappingMatcher(_options);
app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher);
_options.PostWireMockMiddlewareInit?.Invoke(app);
};
Action<IAppBuilder> startup = app =>
{
app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher);
_options.PostWireMockMiddlewareInit?.Invoke(app);
};
foreach (var url in Urls)
{
servers.Add(WebApp.Start(url, startup));
}
IsStarted = true;
// WaitHandle is signaled when the token is cancelled,
// which will be more efficient than Thread.Sleep in while loop
_cts.Token.WaitHandle.WaitOne();
}
catch (Exception e)
foreach (var url in Urls)
{
// Expose exception of starting host, otherwise it's hard to be troubleshooting if keeping quiet
// For example, WebApp.Start will fail with System.MissingMemberException if Microsoft.Owin.Host.HttpListener.dll is being located
// https://stackoverflow.com/questions/25090211/owin-httplistener-not-located/31369857
_runningException = e;
_logger.Error(e.ToString());
}
finally
{
IsStarted = false;
// Dispose all servers in finally block to make sure clean up allocated resource on error happening
servers.ForEach(s => s.Dispose());
servers.Add(WebApp.Start(url, startup));
}
IsStarted = true;
// WaitHandle is signaled when the token is cancelled,
// which will be more efficient than Thread.Sleep in while loop
_cts.Token.WaitHandle.WaitOne();
}
catch (Exception e)
{
// Expose exception of starting host, otherwise it's hard to be troubleshooting if keeping quiet
// For example, WebApp.Start will fail with System.MissingMemberException if Microsoft.Owin.Host.HttpListener.dll is being located
// https://stackoverflow.com/questions/25090211/owin-httplistener-not-located/31369857
_runningException = e;
_logger.Error(e.ToString());
}
finally
{
IsStarted = false;
// Dispose all servers in finally block to make sure clean up allocated resource on error happening
servers.ForEach(s => s.Dispose());
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using System.Linq;
using System.Net;
using Stef.Validation;
using WireMock.Logging;
using WireMock.Matchers;
@@ -74,10 +75,16 @@ namespace WireMock.Owin
var logRequest = false;
IResponseMessage? response = null;
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
try
{
foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null))
foreach (var mapping in _options.Mappings.Values)
{
if (mapping.Scenario is null)
{
continue;
}
// Set scenario start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{
@@ -107,7 +114,7 @@ namespace WireMock.Owin
if (!present || _options.AuthenticationMatcher.IsMatch(authorization.ToString()) < MatchScores.Perfect)
{
_options.Logger.Error("HttpStatusCode set to 401");
response = ResponseMessageBuilder.Create(null, 401);
response = ResponseMessageBuilder.Create(null, HttpStatusCode.Unauthorized);
return;
}
}
@@ -194,7 +201,7 @@ namespace WireMock.Owin
private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response)
{
for (int index = 0; index < mapping.Webhooks.Length; index++)
for (int index = 0; index < mapping.Webhooks?.Length; index++)
{
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
var webhookSender = new WebhookSender(mapping.Settings);
@@ -212,7 +219,7 @@ namespace WireMock.Owin
private void UpdateScenarioState(IMapping mapping)
{
var scenario = _options.Scenarios[mapping.Scenario];
var scenario = _options.Scenarios[mapping.Scenario!];
// Increase the number of times this state has been executed
scenario.Counter++;

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