Compare commits

...

99 Commits

Author SHA1 Message Date
Stef Heyenrath
358590918e 1.11.2 2025-08-27 10:25:31 +02:00
Stef Heyenrath
32afea5d30 Revert JetBrains.Annotations and add System.Text.RegularExpressions to solve CVE (#1355) 2025-08-27 10:04:36 +02:00
Stef Heyenrath
50b3d58a01 1.11.1 2025-08-27 08:47:58 +02:00
Stef Heyenrath
35bf5e94a5 Add System.Net.Http again to solve CVE warning (#1354) 2025-08-27 08:45:24 +02:00
Stef Heyenrath
9fcc9ade10 Add additional try-catch to TypeLoader logic (#1352) 2025-08-27 08:33:01 +02:00
Stef Heyenrath
865bbf2432 WireMock.Net.ProtoBuf: fix version 2025-08-26 15:42:23 +02:00
Stef Heyenrath
560540099e 1.11.0 2025-08-26 07:58:04 +02:00
Stef Heyenrath
e5c4605020 Create WireMock.Net.ProtoBuf project (#1350)
* Create WireMock.Net.ProtoBuf project

* ok

* Update Directory.Build.props

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-26 07:55:02 +02:00
Stef Heyenrath
124d29c86a 1.10.1 2025-08-22 19:58:00 +02:00
Stef Heyenrath
08117e870b Add AtPath and AtAbsolutePath to Assertions projects (#1349)
* Add AtPath and AtAbsolutePath to Assertions projects

* tst
2025-08-22 19:40:59 +02:00
Stef Heyenrath
ddb181cc52 WireMock.Net.Extensions.Routing 2025-08-18 20:47:10 +02:00
Stef Heyenrath
10fdd24fca 1.10.0 2025-08-18 20:22:49 +02:00
Gennadii Saltyshchak
be2ea67b89 Add new package WireMock.Net.Extensions.Routing which provides minimal-API-style routing for WireMock.Net (#1344)
* Add new package WireMock.Net.Extensions.Routing

* Update documentation for WireMock.Net.Extensions.Routing

* Cleanup imports

* Add header to all source files inside WireMock.Net.Extensions.Routing

* Add header to all source files inside WireMock.Net.Extensions.Routing.Tests

* Revert unintended changes

* Remove redundant build configurations

* Remove incorrect links from documentation

* Update nuget package references

* Revert unintended changes

* Migrate to AwesomeAssertions

* Remove redundant project reference

* Adjust formatting

* Migrate to primary constructor

* Refactoring: rename delegate parameter

* Abstract over JSON converter

* Replace WireMock with WireMock.Net in comments

* Move local functions to the bottom of the methods
2025-08-18 19:52:42 +02:00
Stef Heyenrath
60eb519ae2 1.9.1 2025-08-17 10:11:48 +02:00
Stef Heyenrath
22ed94918a Fix generating source code for Scenario and State (#1347)
* Fix generating source code for Scenario and State

* Update src/WireMock.Net.Minimal/Serialization/MappingConverter.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.Minimal/Serialization/MappingConverter.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* .

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-17 10:06:39 +02:00
Stef Heyenrath
faffc56484 Add TimesInSameState to MappingModel (#1345)
* Add TimesInSameState to MappingModel

* fix tests
2025-08-11 08:46:18 +02:00
Stef Heyenrath
a5558777e2 1.9.0 2025-08-10 19:07:24 +02:00
Stef Heyenrath
6722ca40ba Update feature_request.md 2025-08-10 19:02:24 +02:00
Stef Heyenrath
0597a73e0e Create GraphQL project (#1334)
* Create new project for GraphQL

* ...

* .

* ok?

* Update src/WireMock.Net.Shared/Extensions/AnyOfExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* --

* ...

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-10 19:00:22 +02:00
Stef Heyenrath
0d510cdde8 1.8.18 2025-08-04 18:03:44 +02:00
Stef Heyenrath
52a396beef 1.8.18 2025-08-04 18:03:23 +02:00
Sam Fields
6ccfe68686 Fixes an issue with matching JSON bodies as bytes (#1339)
* Fixes an issue with matching JSON bodies as bytes

* Adding tests for exact object matching

* Simplify the check for byte data
2025-08-02 20:11:13 +02:00
Stef Heyenrath
e400e92452 1.8.17 2025-07-23 09:40:55 +02:00
Stef Heyenrath
7a187dfb78 Add more examples for WithGraphQLSchema (#1335) 2025-07-23 09:34:31 +02:00
Stef Heyenrath
e6ff8776fb Make CSharpCodeMatcher public (#1337) 2025-07-23 09:29:53 +02:00
Stef Heyenrath
c32e904f4d 1.8.16 2025-07-19 08:16:34 +02:00
Stef Heyenrath
e80d436dd6 Use corerct Handlebars.Net.Helpers.Xslt (2.5.2) (#1332) 2025-07-18 10:57:58 +02:00
Stef Heyenrath
fcc95ff06f 1.8.15 2025-07-18 08:45:42 +02:00
Stef Heyenrath
020cc15420 Correctly map the Pact Interaction Description property (#1331)
* Correctly map the Pact Interaction Description property

* Update src/WireMock.Net.Minimal/Serialization/PactMapper.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* post

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-18 08:41:04 +02:00
Stef Heyenrath
aeb15725e4 1.8.14 2025-07-13 08:53:53 +02:00
Stef Heyenrath
a06ee6b158 Fix HandlebarsContext.ParseAndEvaluate (#1329) 2025-07-12 11:05:02 +02:00
Stef Heyenrath
b0076b4e81 Implement IMimeMessageData (#1326)
* Implement IMimeMessageData

* 1

* Update src/WireMock.Net.MimePart/Util/MimeKitUtils.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* v1

* v2

* e

* ?

* fix

* if (Array.TrueForAll(_funcs, func => func(value).IsPerfect()))

* Update src/WireMock.Net.Shared/Util/IMimeKitUtils.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.Minimal/Matchers/Request/RequestMessageMultiPartMatcher.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.MimePart/Models/MimeEntityDataWrapper.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Models.Mime.IMimeMessageData? BodyAsMimeMessage { get; }

* Update src/WireMock.Net.MimePart/Util/MimeKitUtils.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.MimePart/Models/MimePartDataWrapper.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.MimePart/Models/MimeMessageDataWrapper.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/WireMock.Net.Shared/Util/IMimeKitUtils.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* .

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-12 09:54:18 +02:00
Stef Heyenrath
6c61f87ef3 Add method CreateHttpClientFactory (#1325)
* Add method CreateHttpClientFactory

* rev
2025-07-08 10:50:30 +02:00
Stef Heyenrath
35cd06b47b Update README.md 2025-06-24 09:31:22 +02:00
Stef Heyenrath
b925c537c7 1.8.13 2025-06-23 08:07:30 +02:00
Stef Heyenrath
f80925c1fb Add Scenario set State method (#1322)
* Add SetScenarioState

* add tests

* summary

* .

* 1.8.13-preview-01

* fix

* fix name
2025-06-23 08:03:11 +02:00
Stef Heyenrath
43cff52b69 1.8.12 2025-06-15 11:50:31 +02:00
Stef Heyenrath
7b93b2668d Fix TypeLoader (#1320)
* no ilmerge

* .

* .

* nullable

* .UsingNuGet

* fix

* .

* directoriesToSearch

* .
2025-06-15 11:44:09 +02:00
Dom Light
70a9180af4 Set description when converting MappingModel to IRespondWithAProvider (#1317)
Adding a mapping with a description to `WireMockServer.WithMapping`
did not include the description to the resulting
`IRespondWithAProvider`, which means that calling
`WireMockServer.SavePact` does not populate the description in the
contract file.

This PR includes the description when mapping from `MappingModel` to
`IRespondWithAProvider`.
2025-06-14 11:13:04 +02:00
Stef Heyenrath
acd6592562 remove some old console projects 2025-06-13 13:07:48 +02:00
Sébastien Crocquesel
2a010dcd42 Use default resource cleaning behavior in test (#1316) 2025-06-12 22:06:58 +02:00
Stef Heyenrath
8151119cca 1.8.11 2025-06-11 12:04:21 +02:00
Stef Heyenrath
77000372c6 Fix for WithTransformer and JsonBody as list (#1315)
* Fix for WithTransformer and JsonBody as list

* Fix WithTransformer when the response BodyAsJson is a List
2025-06-11 11:51:29 +02:00
Stef Heyenrath
ec248a9a78 Fix TestcontainersTests to ignore exception when stopping (#1314) 2025-06-11 11:12:58 +02:00
Stef Heyenrath
2f7e3a3178 Update TestcontainersTests to ignore exception when stopping 2025-06-11 10:21:42 +02:00
Stef Heyenrath
ac9c51e34e Update RandomDataGenerator.Net to 1.0.19 (#1313)
* Update RandomDataGenerator.Net to 1.0.19

* Handlebars.Net.Helpers
2025-06-11 09:00:23 +02:00
Sébastien Crocquesel
8ba243ddcd Bump Testcontainers version to 4.5.0 (#1311)
* Bump Testcontainers version to 4.5.0

The Testcontainers dependency Docker.DotNet was bumped to 3.128.1 and is not binary compatible with previous version.
When a user has a direct dependency on Testcontainers 4.5.0, WireMock.Net.Testcontainers fails with :

System.MissingMethodException : Method not found: 'Docker.DotNet.DockerClient Docker.DotNet.DockerClientConfiguration.CreateClient(System.Version)'

* Bump System.Net.Http.Json version to 8.0.1

Minimum required version for Testcontainers 4.5.0

* Do not dispose null container
2025-06-10 22:23:56 +02:00
Stef Heyenrath
d4b95e73ea Remove unit test which uses postman-echo 2025-06-10 13:16:24 +02:00
Stef Heyenrath
f9ae045847 Images/Icons 2025-06-10 12:23:07 +02:00
Stef Heyenrath
05b5876b5c 1.8.10 2025-06-10 08:15:22 +02:00
Stef Heyenrath
c1bd2d315f Update AwesomeAssertions to version 9 (#1309) 2025-06-06 21:06:38 +02:00
Stef Heyenrath
8917a6eaaa For some projects, change dependency to WireMock.Net.Minimal (#1308) 2025-06-06 11:22:34 +02:00
Stef Heyenrath
3cc9040f51 Update RequestModelBuilder (add WithHeader) (#1306)
* Update RequestModelBuilder (add WithHeader)

* rejectOnMatch

* fix
2025-06-05 12:24:40 +02:00
Stef Heyenrath
6136bc177c 1.8.9 2025-05-28 07:18:51 +02:00
Stef Heyenrath
86d4717216 Add option to provide X509Certificate (#1303)
* Add option to provide X509CertificateRawData

* X509Certificate

* remove X509CertificateRawData
2025-05-28 07:15:46 +02:00
Stef Heyenrath
3438539138 1.8.8 2025-05-24 12:34:30 +02:00
Stef Heyenrath
96eca4262a Create WireMock.Net.MimePart project (#1300)
* Create WireMock.Net.MimePart project

* .

* REFACTOR

* ILRepack

* --

* ...

* x

* x

* .

* fix

* public class MimePartMatcher

* shared

* min

* .

* <!--<DelaySign>true</DelaySign>-->

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-24 12:17:42 +02:00
Stef Heyenrath
c15206ecd8 Update README.md [codecov] 2025-05-22 15:30:01 +02:00
Stef Heyenrath
ec15c544c4 Update README.md (fix codefactor link) 2025-05-22 08:46:11 +02:00
Stef Heyenrath
339d3ab3a8 Fix CSharpFormatterTests 2025-05-22 08:42:23 +02:00
Stef Heyenrath
001ba03ee9 1.8.7 2025-05-22 08:22:48 +02:00
Stef Heyenrath
17545da2c3 Add extra unit test test to CSharpFormatterTests 2025-05-22 08:14:45 +02:00
Asaf Agami
b4279be3cb Fix exception when converting json array to C# code (#1301) 2025-05-22 07:54:58 +02:00
Stef Heyenrath
d628ce2270 Fix BodyParser to correctly check for json (#1297)
* Fix BodyParser to correctly check for json

* JsonUtils
2025-05-21 17:28:29 +02:00
Stef Heyenrath
1e23c58bf2 Use TinyMapper.Signed (#1299)
* Use TinyMapper.Signed

* <PackageReference Include="TinyMapper.Signed" Version="4.0.0" />
2025-05-17 18:29:03 +02:00
Stef Heyenrath
9b5801f828 1.8.6 2025-05-15 20:16:17 +02:00
Stef Heyenrath
61b6eb8752 Content-Type multipart/form-data header should also be proxied (#1296) 2025-05-15 18:21:21 +02:00
Stef Heyenrath
baa33552e9 1.8.5 2025-05-14 07:34:04 +02:00
Stef Heyenrath
492f01ade1 Add more tests for WireMockOpenApiParser (#1294) 2025-05-13 22:11:25 +02:00
Stef Heyenrath
7596967fcc Grpc: Fix parsing null value for google.protobuf.Timestamp (#1293)
* Add another example for Grpc client + mapping

* <PackageReference Include="ProtoBufJsonConverter" Version="0.9.0" />
2025-05-10 12:53:18 +02:00
Stef Heyenrath
56c058fe24 Cleanup old WireMock.Net.OpenApiParser 2025-05-10 08:10:20 +02:00
Stef
b43be28b5f 1.8.4 2025-05-08 20:15:23 +02:00
Stef Heyenrath
5ed09d84a3 Use ILRepack to include Microsoft.OpenApi as internal (#1290)
* .

* Use ILRepack to include Microsoft.OpenApi as internal

* ...

* OpenApiSpecificationVersion

* .

* 080

* 4
2025-05-08 20:11:41 +02:00
Stef
cfcc55d2dd 1.8.3 2025-05-06 21:47:29 +02:00
Stef Heyenrath
249b3562ab Update AzureADAuthenticationMatcher to support V2 Azure AAD tokens (#1288)
* Update AzureADAuthenticationMatcher to support V2 Azure AAD tokens

* fix ;-)

* add tests

* Update test/WireMock.Net.Tests/Authentication/MockJwtSecurityTokenHandler.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* .

* WIREMOCK_AAD_TENANT

* update logging

* throw new SecurityTokenInvalidIssuerException($"tenant {extractedTenant} does not match {_tenant}.");

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-06 18:49:21 +02:00
Stef
cfc13b2449 1.8.2 2025-05-05 10:23:14 +02:00
Stef Heyenrath
4303706530 Update ProtoBufJsonConverter to fix conflict for 'MessageOptions' (#1291)
* Update ProtoBufJsonConverter to fix conflict for 'MessageOptions'

* <PackageReference Include="ProtoBufJsonConverter" Version="0.8.0" />
2025-05-05 10:21:15 +02:00
Stef Heyenrath
5c8105b50d move 'WireMock.Net.OpenApiParser.Preview' to ''src-preview' folder 2025-05-02 09:15:59 +02:00
Stef Heyenrath
630ffab56e Do not generate NuGet for WireMock.Net.OpenApiParser.Preview 2025-05-02 08:50:32 +02:00
Stef Heyenrath
c181d0286a Do not generate NuGet for WireMock.Net.OpenApiParser.Preview 2025-05-02 08:41:51 +02:00
Stef Heyenrath
16dab99175 1.8.1 2025-05-02 07:29:11 +02:00
Stef Heyenrath
cf0dcf5855 Revert changes to WireMock.Net.OpenApiParser (#1289)
* Revert changes to WireMock.Net.OpenApiParser

* revert
2025-05-02 07:18:35 +02:00
Stef
e7310fbc7b 1.8.0 2025-04-28 19:35:48 +02:00
Jonathan Mezach
8a07286b89 Add an launch inspector command to Aspire Dashboard (#1283)
* Upgrade to Aspire 9.2.0

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Remove workload installs from CI pipeline

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Missed package upgrade

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Fix usings

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Add Open Inspector command

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Fix broken test

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* PR comments

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* More PR comments

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

---------

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>
2025-04-25 20:23:19 +02:00
Emil Tang Kristensen
9392069f8a Enable support for WireMock Middleware in Hosted Services (#1285) 2025-04-25 16:35:55 +02:00
Stef Heyenrath
0fd190b5a3 Fix Changelog 2025-04-24 20:17:15 +02:00
Stef Heyenrath
4368e3cde6 1.7.x (#1268)
* Fix construction of path in OpenApiParser (#1265)

* Server-Sent Events (#1269)

* Server Side Events

* fixes

* await HandleSseStringAsync(responseMessage, response, bodyData);

* 1.7.5-preview-01

* IBlockingQueue

* 1.7.5-preview-02 (03 April 2025)

* IBlockingQueue

* ...

* Support OpenApi V31 (#1279)

* Support OpenApi V31

* Update src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fx

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add ProtoDefinitionHelper.FromDirectory (#1263)

* Add ProtoDefinitionHelper.FromDirectory

* .

* unix-windows

* move test

* imports in the proto files indeed should use a forward slash

* updates

* .

* private Func<IdOrTexts> ProtoDefinitionFunc()

* OpenTelemetry

* .

* fix path utils

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-23 11:51:44 +02:00
Stef Heyenrath
fc0f82db33 Add HandlebarsSettings (#1271)
* Add HandlebarsSettings class

* DefaultAllowedHandlebarsHelpers

* HB - 2.5.0-preview-01

* readme

* fix

* readme

* Handlebars.Net.Helpers Version="2.5.0"
2025-04-23 07:47:37 +02:00
Stef Heyenrath
beabba4064 Add extra unit tests for PR #1278 2025-04-23 07:47:07 +02:00
jollyjoyce1995
d9a7e80360 changed null check in JSONPathMatcher and JmesPathMatcher to ensure that the body is not an empty string (the json parse would throw an exception at this point) (#1278) 2025-04-23 07:30:52 +02:00
Stef Heyenrath
66a048a487 update readme for WireMock.Net.AwesomeAssertions 2025-04-23 07:30:21 +02:00
Francesco Venturoli
04d53f3a9e feat(awesome-assertions): Added new project WireMock.Net.AwesomeAssertions (#1273)
* feat(awesome-assertions): Added new project WireMock.Net.AwesomeAssertions

* feat(awesome-assertions): Applied dotnet naming convention for private readonly fields

---------

Co-authored-by: Francesco Venturoli <f.venturoli@crif.com>
2025-04-22 22:51:40 +02:00
Stef Heyenrath
a8562fda32 Use vmImage ubuntu-22.04 and install aspire workload in Azure DevOps CI-CD pipeline (#1282)
* Install aspire workload in Azure DevOps CI-CD pipeline

* vmImage: 'ubuntu-22.04'
2025-04-22 22:47:43 +02:00
Stef Heyenrath
5abb424d3c Add extra JsonPartialWildcardMatcher Tests (#1267)
* Add extra JsonPartialWildcardMatcher Tests

* responseText.Should().Contain
2025-04-02 08:57:44 +02:00
Stef Heyenrath
db158bcc7e Update readme 2025-03-04 18:17:09 +01:00
Stef Heyenrath
0effda3cfa 1.8.0-prview-01 (Update the usage from the custom Handlebars.Net File helper) 2025-03-04 18:11:13 +01:00
Stef Heyenrath
ff36c1ee6f Merge commit from fork 2025-03-04 17:58:38 +01:00
Stef Heyenrath
be55022a2a 1.7.4 2025-02-27 07:15:02 +01:00
Stef Heyenrath
7c68fc1d94 Add ToArray() to ConcurrentObservableCollection (#1256)
* Add ToArray() to ConcurrentObservableCollection

* ---
2025-02-27 07:12:05 +01:00
517 changed files with 22381 additions and 14427 deletions

View File

@@ -1,15 +0,0 @@
{
"TestRunner": "",
"TestPlatform": "x86",
"TestApartmentState": "STA",
"TestSettings": "",
"ExcludeAttributes": "System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute",
"ExcludeFiles": "",
"ExcludeDirectories": "",
"Filters": "+[*]*",
"IsIncludingSolutionAssemblies": true,
"IsExcludingTestAssemblies": false,
"IsCoveringByTest": true,
"IsMergingByHash": true,
"IsSkippingAutoProps": true
}

View File

@@ -8,7 +8,7 @@ assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
@@ -17,7 +17,7 @@ A clear and concise description of what you want to happen.
A clear and concise description of any alternative solutions or features you've considered.
**Is your feature request supported by [WireMock (java version)](https://www.wiremock.org)? Please provide details.**
Provide relevant information if requested feature is supported in [Handlebarsjs](https://handlebarsjs.com/) but is missing in our implementation.
Provide relevant information if requested feature is supported but is missing in this implementation.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,5 +1,8 @@
name: CreateRelease
permissions:
contents: write
on:
push:
tags:
@@ -10,6 +13,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

View File

@@ -22,6 +22,9 @@ jobs:
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Tests.UsingNuGet'
run: dotnet test './test/WireMock.Net.Tests.UsingNuGet/WireMock.Net.Tests.UsingNuGet.csproj' -c Release
- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0
@@ -46,6 +49,9 @@ jobs:
- name: 'WireMock.Net.Tests'
run: dotnet test './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj' -c Release --framework net8.0
- name: 'WireMock.Net.Tests.UsingNuGet'
run: dotnet test './test/WireMock.Net.Tests.UsingNuGet/WireMock.Net.Tests.UsingNuGet.csproj' -c Release
- name: 'WireMock.Net.TUnitTests'
run: dotnet test './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj' -c Release --framework net8.0

11
.vscode/launch.json vendored
View File

@@ -1,11 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

17
.vscode/tasks.json vendored
View File

@@ -1,17 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"taskName": "build_WireMock.Net.StandAlone.NETCoreApp",
"command": "dotnet build ${workspaceRoot}/examples/WireMock.Net.StandAlone.NETCoreApp/WireMock.Net.StandAlone.NETCoreApp.csproj -f netcoreapp2.0 ",
"type": "shell",
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,13 +4,13 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.7.3</VersionPrefix>
<Version>1.11.2</Version>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../PackageReleaseNotes.txt"))</PackageReleaseNotes>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl>
<RepositoryUrl>https://github.com/wiremock/WireMock.Net</RepositoryUrl>
<ApplicationIcon>../../resources/WireMock.Net-Logo.ico</ApplicationIcon>
<PackageReadmeFile>PackageReadme.md</PackageReadmeFile>
<LangVersion>12.0</LangVersion>
@@ -58,7 +58,7 @@
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167">
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.15.0.120848">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

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

View File

@@ -15,13 +15,13 @@ Lightweight Http Mocking Server for .NET, inspired by WireMock.org (from the Jav
### :star: Stubbing
A core feature of WireMock.Net is the ability to return predefined HTTP responses for requests matching criteria.
See [Wiki : Stubbing](https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing).
See [Wiki : Stubbing](https://github.com/wiremock/WireMock.Net/wiki/Stubbing).
### :star: Request Matching
WireMock.Net support advanced request-matching logic, see [Wiki : Request Matching](https://github.com/WireMock-Net/WireMock.Net/wiki/Request-Matching).
WireMock.Net support advanced request-matching logic, see [Wiki : Request Matching](https://github.com/wiremock/WireMock.Net/wiki/Request-Matching).
### :star: Response Templating
The response which is returned WireMock.Net can be changed using templating. This is described here [Wiki : Response Templating](https://github.com/WireMock-Net/WireMock.Net/wiki/Response-Templating).
The response which is returned WireMock.Net can be changed using templating. This is described here [Wiki : Response Templating](https://github.com/wiremock/WireMock.Net/wiki/Response-Templating).
### :star: Admin API Reference
The WireMock admin API provides functionality to define the mappings via a http interface see [Wiki : Admin API Reference](https://github.com/StefH/WireMock.Net/wiki/Admin-API-Reference).
@@ -34,10 +34,10 @@ You can use your favorite test framework and use WireMock within your tests, see
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
### Unit/Integration Testing using Testcontainers.DotNet
See [Wiki : WireMock.Net.Testcontainers](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) on how to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
See [Wiki : WireMock.Net.Testcontainers](https://github.com/wiremock/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) on how to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
### Unit/Integration Testing using an an Aspire Distributed Application
See [Wiki : WireMock.Net.Aspire](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Aspire) on how to use WireMock.Net as an Aspire Hosted application to do Unit/Integration testing.
See [Wiki : WireMock.Net.Aspire](https://github.com/wiremock/WireMock.Net/wiki/Using-WireMock.Net.Aspire) on how to use WireMock.Net as an Aspire Hosted application to do Unit/Integration testing.
#### As a dotnet tool
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
@@ -46,17 +46,17 @@ It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
#### As a Windows Service
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/wiremock/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
#### As a Web Job in Azure or application in IIS
See this link [WireMock-as-a-(Azure)-Web-App](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-(Azure)-Web-App)
See this link [WireMock-as-a-(Azure)-Web-App](https://github.com/wiremock/WireMock.Net/wiki/WireMock-as-a-(Azure)-Web-App)
#### In a docker container
There is also a Linux and Windows-Nano container available at [hub.docker.com](https://hub.docker.com/r/sheyenrath).
For more details see also [Docker](https://github.com/WireMock-Net/WireMock.Net-docker).
For more details see also [Docker](https://github.com/wiremock/WireMock.Net-docker).
#### HTTPS / SSL
More details on using HTTPS (SSL) can be found here [Wiki : HTTPS](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-HTTPS-(SSL))
More details on using HTTPS (SSL) can be found here [Wiki : HTTPS](https://github.com/wiremock/WireMock.Net/wiki/Using-HTTPS-(SSL))
## :books: Documentation
For more info, see also this WIKI page: [What is WireMock.Net](https://github.com/WireMock-Net/WireMock.Net/wiki/What-Is-WireMock.Net).
For more info, see also this WIKI page: [What is WireMock.Net](https://github.com/wiremock/WireMock.Net/wiki/What-Is-WireMock.Net).

View File

@@ -3,4 +3,4 @@
- #{{Number}} {{Title}}{{#if Labels}} [{{join Labels ", "}}]{{/if}}
{{/each}}
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -1,5 +1,9 @@
# 1.7.3 (24 February 2025)
- #1253 Update QueryStringParser to support param with equal but no value [bug]
- #1247 API call isn't matched when using an empty query string parameter [bug]
# 1.11.2 (27 August 2025)
- #1352 Add additional try-catch to TypeLoader logic [feature]
- #1354 Add System.Net.Http again to solve CVE warning [bug]
- #1355 Revert JetBrains.Annotations and add System.Text.RegularExpressions t&#8230; [bug]
- #1071 Split WireMock into multiple nuget packages depending on features [feature]
- #1351 Version 1.11.0 seems to have a dependency to non-existing version of JetBrans.Annotations [bug]
- #1353 1.11.0: NU1903: Warning As Error: Package 'System.Net.Http' 4.3.0 has a known high severity vulnerability, https://github.com/advisories/GHSA-7jgj-8wvc-jh57 [bug]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md
The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -1,7 +1,7 @@
# WireMock.Net
A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based [WireMock](http://WireMock.org).
# ![Project Icon](./resources/logo_32x32.png) WireMock.Net
A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based [WireMock](http://wiremock.org).
For more info, see also this WIKI page: [What is WireMock.Net](https://github.com/WireMock-Net/WireMock.Net/wiki/What-Is-WireMock.Net).
For more info, see also this WIKI page: [What is WireMock.Net](https://github.com/wiremock/WireMock.Net/wiki/What-Is-WireMock.Net).
## :star: Key Features
* HTTP response stubbing, matchable on URL/Path, headers, cookies and body content patterns
@@ -26,35 +26,45 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
| --- | --- |
| ***Project*** | &nbsp; |
| &nbsp;&nbsp;**Chat** | [![Slack](https://badgen.net/badge/icon/slack?icon=slack&label)](https://slack.wiremock.org/) [![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby) |
| &nbsp;&nbsp;**Issues** | [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues) |
| &nbsp;&nbsp;**Issues** | [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/wiremock/WireMock.Net/issues) |
| | |
| ***Quality*** | &nbsp; |
| &nbsp;&nbsp;**Build Azure** | [![Build Status Azure](https://stef.visualstudio.com/WireMock.Net/_apis/build/status/WireMock.Net)](https://stef.visualstudio.com/WireMock.Net/_build/latest?definitionId=7) |
| &nbsp;&nbsp;**Quality** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=alert_status)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net) [![CodeFactor](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net/badge)](https://www.codefactor.io/repository/github/wiremock-net/wiremock.net) |
| &nbsp;&nbsp;**Quality** | [![Sonar Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=alert_status)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net) [![CodeFactor](https://www.codefactor.io/repository/github/wiremock/wiremock.net/badge)](https://www.codefactor.io/repository/github/wiremock/wiremock.net) |
| &nbsp;&nbsp;**Sonar Bugs** | [![Sonar Bugs](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=bugs)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=BUG) [![Sonar Code Smells](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=code_smells)](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=CODE_SMELL) |
| &nbsp;&nbsp;**Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=coverage)](https://sonarcloud.io/component_measures?id=WireMock-Net_WireMock.Net&metric=coverage) [![codecov](https://codecov.io/gh/WireMock-Net/WireMock.Net/branch/master/graph/badge.svg)](https://codecov.io/gh/WireMock-Net/WireMock.Net)|
| &nbsp;&nbsp;**Coverage** | [![Sonar Coverage](https://sonarcloud.io/api/project_badges/measure?project=WireMock-Net_WireMock.Net&metric=coverage)](https://sonarcloud.io/component_measures?id=WireMock-Net_WireMock.Net&metric=coverage) [![codecov](https://codecov.io/gh/wiremock/WireMock.Net/branch/master/graph/badge.svg)](https://codecov.io/gh/wiremock/WireMock.Net)|
| &nbsp;&nbsp;**TIOBE** | [TIOBE Quality Indicator](https://ticsdemo.tiobe.com/tiobeweb/DEMO/TqiDashboard.html#axes=Project(WireMock.Net),Sub()&metric=tqi)
### :package: NuGet packages
| | Official | Preview [:information_source:](https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions) |
| | Official | Preview [:information_source:](https://github.com/wiremock/WireMock.Net/wiki/MyGet-preview-versions) |
| - | - | - |
| &nbsp;&nbsp;**WireMock.Net** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net)](https://www.nuget.org/packages/WireMock.Net) | [![MyGet Badge WireMock.Net](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net)
| &nbsp;&nbsp;**WireMock.Net.Minimal** 🔺| [![NuGet Badge WireMock.Net.Minimal](https://img.shields.io/nuget/v/WireMock.Net.Minimal)](https://www.nuget.org/packages/WireMock.Net.Minimal) | [![MyGet Badge WireMock.Net](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Minimal?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Minimal)
| &nbsp;&nbsp;**WireMock.Net.StandAlone** | [![NuGet Badge WireMock.Net](https://img.shields.io/nuget/v/WireMock.Net.StandAlone)](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [![MyGet Badge WireMock.Net.StandAlone](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.StandAlone?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
| &nbsp;&nbsp;**WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://img.shields.io/nuget/v/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Testcontainers?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
| &nbsp;&nbsp;**WireMock.Net.Aspire** | [![NuGet Badge WireMock.Net.Aspire](https://img.shields.io/nuget/v/WireMock.Net.Aspire)](https://www.nuget.org/packages/WireMock.Net.Aspire) | [![MyGet Badge WireMock.Net.Aspire](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Aspire?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire)
| &nbsp;&nbsp;**WireMock.Net.AspNetCore.Middleware** | [![NuGet Badge WireMock.Net.AspNetCore.Middleware](https://img.shields.io/nuget/v/WireMock.Net.AspNetCore.Middleware)](https://www.nuget.org/packages/WireMock.Net.AspNetCore.Middleware) | [![MyGet Badge WireMock.Net.AspNetCore.Middleware](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.AspNetCore.Middleware?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.AspNetCore.Middleware)
| | | |
| &nbsp;&nbsp;**WireMock.Net.AwesomeAssertions** | [![NuGet Badge WireMock.Net.AwesomeAssertions](https://img.shields.io/nuget/v/WireMock.Net.AwesomeAssertions)](https://www.nuget.org/packages/WireMock.Net.AwesomeAssertions) | [![MyGet Badge WireMock.Net.AwesomeAssertions](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.AwesomeAssertions?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.AwesomeAssertions)
| &nbsp;&nbsp;**WireMock.Net.FluentAssertions** | [![NuGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/nuget/v/WireMock.Net.FluentAssertions)](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [![MyGet Badge WireMock.Net.FluentAssertions](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.FluentAssertions?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions)
| &nbsp;&nbsp;**WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://img.shields.io/nuget/v/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.xUnit?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
| &nbsp;&nbsp;**WireMock.Net.TUnit** | [![NuGet Badge WireMock.Net.TUnit](https://img.shields.io/nuget/v/WireMock.Net.TUnit)](https://www.nuget.org/packages/WireMock.Net.TUnit) | [![MyGet Badge WireMock.Net.TUnit](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.TUnit?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.TUnit)
| | | |
| &nbsp;&nbsp;**WireMock.Net.Extensions.Routing** | [![NuGet Badge WireMock.Net.Extensions.Routing](https://img.shields.io/nuget/v/WireMock.Net.Extensions.Routing)](https://www.nuget.org/packages/WireMock.Net.Extensions.Routing) | [![MyGet Badge WireMock.Net.Extensions.Routing](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Extensions.Routing?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Extensions.Routing)
| &nbsp;&nbsp;**WireMock.Net.Matchers.CSharpCode** | [![NuGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/nuget/v/WireMock.Net.Matchers.CSharpCode)](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [![MyGet Badge WireMock.Net.Matchers.CSharpCode](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.Matchers.CSharpCode?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
| &nbsp;&nbsp;**WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/nuget/v/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.OpenApiParser?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
| &nbsp;&nbsp;**WireMock.Net.MimePart** | [![NuGet Badge WireMock.Net.MimePart](https://img.shields.io/nuget/v/WireMock.Net.MimePart)](https://www.nuget.org/packages/WireMock.Net.MimePart) | [![MyGet Badge WireMock.Net.MimePart](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.MimePart?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.MimePart)
| &nbsp;&nbsp;**WireMock.Net.GraphQL** | [![NuGet Badge WireMock.Net.GraphQL](https://img.shields.io/nuget/v/WireMock.Net.GraphQL)](https://www.nuget.org/packages/WireMock.Net.GraphQL) | [![MyGet Badge WireMock.Net.GraphQL](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.GraphQL?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.GraphQL)
| &nbsp;&nbsp;**WireMock.Net.ProtoBuf** | [![NuGet Badge WireMock.Net.ProtoBuf](https://img.shields.io/nuget/v/WireMock.Net.ProtoBuf)](https://www.nuget.org/packages/WireMock.Net.ProtoBuf) | [![MyGet Badge WireMock.Net.ProtoBuf](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.ProtoBuf?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.ProtoBuf)
| | | |
| &nbsp;&nbsp;**WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://img.shields.io/nuget/v/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Net.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
| &nbsp;&nbsp;**WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://img.shields.io/nuget/v/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://img.shields.io/myget/wiremock-net/vpre/WireMock.Org.RestClient?includePreReleases=true&label=MyGet)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
<br />
🔺 **WireMock.Net.Minimal** does not include *WireMock.Net.MimePart*, *WireMock.Net.GraphQL* and *WireMock.Net.ProtoBuf*.
---
## :exclamation: Breaking changes
@@ -64,20 +74,32 @@ A breaking change is introduced which is related to System.Linq.Dynamic.Core Dyn
- The `LinqMatcher` is not allowed.
- The [Handlebars.Net.Helpers.DynamicLinq](https://www.nuget.org/packages/Handlebars.Net.Helpers.DynamicLinq) package is not included anymore.
### 1.8.0
Some breaking changes are introduced in this version:
#### Handlebars.Net `File`-helper
By default, the internal Handlebars.Net `File`-helper is not allowed anymore because of potential security issues.
To still enable this feature, you need to set the `AllowedCustomHandlebarHelpers` property to `File` in the `HandlebarsSettings` property in `WireMockServerSettings`.
#### Handlebars.Net `Environment`-helper
By default, the Handlebars.Net `Environment`-helper is not automatically allowed anymore because of potential security issues.
To still enable this feature, you need to add the `Environment` category to the `AllowedHandlebarsHelpers` list-property in the `HandlebarsSettings` property in `WireMockServerSettings`.
---
## :memo: Development
For the supported frameworks and build information, see [this](https://github.com/WireMock-Net/WireMock.Net/wiki/Development-Information) page.
For the supported frameworks and build information, see [this](https://github.com/wiremock/WireMock.Net/wiki/Development-Information) page.
## :star: Stubbing
A core feature of WireMock.Net is the ability to return predefined HTTP responses for requests matching criteria.
See [Wiki : Stubbing](https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing).
See [Wiki : Stubbing](https://github.com/wiremock/WireMock.Net/wiki/Stubbing).
## :star: Request Matching
WireMock.Net support advanced request-matching logic, see [Wiki : Request Matching](https://github.com/WireMock-Net/WireMock.Net/wiki/Request-Matching).
WireMock.Net support advanced request-matching logic, see [Wiki : Request Matching](https://github.com/wiremock/WireMock.Net/wiki/Request-Matching).
## :star: Response Templating
The response which is returned WireMock.Net can be changed using templating. This is described here [Wiki : Response Templating](https://github.com/WireMock-Net/WireMock.Net/wiki/Response-Templating).
The response which is returned WireMock.Net can be changed using templating. This is described here [Wiki : Response Templating](https://github.com/wiremock/WireMock.Net/wiki/Response-Templating).
## :star: Admin API Reference
The WireMock admin API provides functionality to define the mappings via a http interface see [Wiki : Admin API Reference](https://github.com/StefH/WireMock.Net/wiki/Admin-API-Reference).
@@ -90,10 +112,10 @@ You can use your favorite test framework and use WireMock within your tests, see
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
### Unit/Integration Testing using Testcontainers.DotNet
See [Wiki : WireMock.Net.Testcontainers](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) on how to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
See [Wiki : WireMock.Net.Testcontainers](https://github.com/wiremock/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) on how to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
### Unit/Integration Testing using an an Aspire Distributed Application
See [Wiki : WireMock.Net.Aspire](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Aspire) on how to use WireMock.Net as an Aspire Hosted application to do Unit/Integration testing.
See [Wiki : WireMock.Net.Aspire](https://github.com/wiremock/WireMock.Net/wiki/Using-WireMock.Net.Aspire) on how to use WireMock.Net as an Aspire Hosted application to do Unit/Integration testing.
### As a dotnet tool
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
@@ -102,14 +124,19 @@ It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
### As a Windows Service
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/wiremock/WireMock.Net/wiki/WireMock-as-a-Windows-Service).
### As a Web Job in Azure or application in IIS
See this link [WireMock-as-a-(Azure)-Web-App](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-(Azure)-Web-App)
See this link [WireMock-as-a-(Azure)-Web-App](https://github.com/wiremock/WireMock.Net/wiki/WireMock-as-a-(Azure)-Web-App)
### In a docker container
There is also a Linux and Windows-Nano container available at [hub.docker.com](https://hub.docker.com/r/sheyenrath).
For more details see also [Docker](https://github.com/WireMock-Net/WireMock.Net-docker).
For more details see also [Docker](https://github.com/wiremock/WireMock.Net-docker).
#### HTTPS / SSL
More details on using HTTPS (SSL) can be found here [Wiki : HTTPS](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-HTTPS-(SSL))
More details on using HTTPS (SSL) can be found here [Wiki : HTTPS](https://github.com/wiremock/WireMock.Net/wiki/Using-HTTPS-(SSL))
---
## Powered by
[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource)

View File

@@ -38,16 +38,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.Proxy.Net452", "examples\WireMock.Net.Console.Proxy.Net452\WireMock.Net.Console.Proxy.Net452.csproj", "{26433A8F-BF01-4962-97EB-81BFFBB61096}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Service", "examples\Wiremock.Net.Service\WireMock.Net.Service.csproj", "{7F0B2446-0363-4720-AF46-F47F83B557DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.Net452.Classic", "examples\WireMock.Net.Console.Net452.Classic\WireMock.Net.Console.Net452.Classic.csproj", "{668F689E-57B4-422E-8846-C0FF643CA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.RequestLogTest", "examples\WireMock.Net.Console.RequestLogTest\WireMock.Net.Console.RequestLogTest.csproj", "{A9D039B9-7509-4CF1-9EFD-87EB82998575}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{D3804228-91F4-4502-9595-39584E5AADAD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.OpenApiParser.ConsoleApp", "examples\WireMock.Net.OpenApiParser.ConsoleApp\WireMock.Net.OpenApiParser.ConsoleApp.csproj", "{5C09FB93-1535-4F92-AF26-21E8A061EE4A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.FluentAssertions", "src\WireMock.Net.FluentAssertions\WireMock.Net.FluentAssertions.csproj", "{B6269AAC-170A-4346-8B9A-579DED3D9A95}"
@@ -128,6 +122,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TestWebApplica
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Middleware.Tests", "test\WireMock.Net.Middleware.Tests\WireMock.Net.Middleware.Tests.csproj", "{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.AwesomeAssertions", "src\WireMock.Net.AwesomeAssertions\WireMock.Net.AwesomeAssertions.csproj", "{7753670F-7C7F-44BF-8BC7-08325588E60C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{E5B03EEF-822C-4295-952B-4479AD30082B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.MimePart", "src\WireMock.Net.MimePart\WireMock.Net.MimePart.csproj", "{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Shared", "src\WireMock.Net.Shared\WireMock.Net.Shared.csproj", "{D3804228-91F4-4502-9595-39584E5A0177}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Minimal", "src\WireMock.Net.Minimal\WireMock.Net.Minimal.csproj", "{BFEF8990-65B3-4274-310F-7355F0B84035}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.ConsoleApp.UsingNuGet", "examples\WireMock.Net.ConsoleApp.UsingNuGet\WireMock.Net.ConsoleApp.UsingNuGet.csproj", "{1F80A6E6-D146-4E40-9EA8-49DB8494239F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Tests.UsingNuGet", "test\WireMock.Net.Tests.UsingNuGet\WireMock.Net.Tests.UsingNuGet.csproj", "{BBA332C6-28A9-42E7-9C4D-A0816E52A198}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.GraphQL", "src\WireMock.Net.GraphQL\WireMock.Net.GraphQL.csproj", "{B6269AAC-170A-4346-8B9A-444DED3D9A45}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Extensions.Routing.Tests", "test\WireMock.Net.Extensions.Routing.Tests\WireMock.Net.Extensions.Routing.Tests.csproj", "{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Extensions.Routing", "src\WireMock.Net.Extensions.Routing\WireMock.Net.Extensions.Routing.csproj", "{1E874C8F-08A2-493B-8421-619F9A6E9E77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.ProtoBuf", "src\WireMock.Net.ProtoBuf\WireMock.Net.ProtoBuf.csproj", "{B47413AA-55D3-49A7-896A-17ADBFF72407}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -158,26 +174,14 @@ Global
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|Any CPU.Build.0 = Release|Any CPU
{26433A8F-BF01-4962-97EB-81BFFBB61096}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26433A8F-BF01-4962-97EB-81BFFBB61096}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26433A8F-BF01-4962-97EB-81BFFBB61096}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26433A8F-BF01-4962-97EB-81BFFBB61096}.Release|Any CPU.Build.0 = Release|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.Build.0 = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA268}.Release|Any CPU.Build.0 = Release|Any CPU
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Release|Any CPU.Build.0 = Release|Any CPU
{D3804228-91F4-4502-9595-39584E5AADAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3804228-91F4-4502-9595-39584E5AADAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3804228-91F4-4502-9595-39584E5AADAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3804228-91F4-4502-9595-39584E5AADAD}.Release|Any CPU.Build.0 = Release|Any CPU
{5C09FB93-1535-4F92-AF26-21E8A061EE4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5C09FB93-1535-4F92-AF26-21E8A061EE4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5C09FB93-1535-4F92-AF26-21E8A061EE4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -302,6 +306,50 @@ Global
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5}.Release|Any CPU.Build.0 = Release|Any CPU
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.Build.0 = Release|Any CPU
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.Build.0 = Release|Any CPU
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Release|Any CPU.Build.0 = Release|Any CPU
{D3804228-91F4-4502-9595-39584E5A0177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3804228-91F4-4502-9595-39584E5A0177}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3804228-91F4-4502-9595-39584E5A0177}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3804228-91F4-4502-9595-39584E5A0177}.Release|Any CPU.Build.0 = Release|Any CPU
{BFEF8990-65B3-4274-310F-7355F0B84035}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFEF8990-65B3-4274-310F-7355F0B84035}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFEF8990-65B3-4274-310F-7355F0B84035}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFEF8990-65B3-4274-310F-7355F0B84035}.Release|Any CPU.Build.0 = Release|Any CPU
{1F80A6E6-D146-4E40-9EA8-49DB8494239F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F80A6E6-D146-4E40-9EA8-49DB8494239F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F80A6E6-D146-4E40-9EA8-49DB8494239F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F80A6E6-D146-4E40-9EA8-49DB8494239F}.Release|Any CPU.Build.0 = Release|Any CPU
{BBA332C6-28A9-42E7-9C4D-A0816E52A198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBA332C6-28A9-42E7-9C4D-A0816E52A198}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBA332C6-28A9-42E7-9C4D-A0816E52A198}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBA332C6-28A9-42E7-9C4D-A0816E52A198}.Release|Any CPU.Build.0 = Release|Any CPU
{B6269AAC-170A-4346-8B9A-444DED3D9A45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6269AAC-170A-4346-8B9A-444DED3D9A45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6269AAC-170A-4346-8B9A-444DED3D9A45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6269AAC-170A-4346-8B9A-444DED3D9A45}.Release|Any CPU.Build.0 = Release|Any CPU
{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C}.Release|Any CPU.Build.0 = Release|Any CPU
{1E874C8F-08A2-493B-8421-619F9A6E9E77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E874C8F-08A2-493B-8421-619F9A6E9E77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E874C8F-08A2-493B-8421-619F9A6E9E77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E874C8F-08A2-493B-8421-619F9A6E9E77}.Release|Any CPU.Build.0 = Release|Any CPU
{B47413AA-55D3-49A7-896A-17ADBFF72407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B47413AA-55D3-49A7-896A-17ADBFF72407}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B47413AA-55D3-49A7-896A-17ADBFF72407}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B47413AA-55D3-49A7-896A-17ADBFF72407}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -313,11 +361,8 @@ Global
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{31DC2EF8-C3FE-467D-84BE-FB5D956E612E} = {0BB8B634-407A-4610-A91F-11586990767A}
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{26433A8F-BF01-4962-97EB-81BFFBB61096} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{7F0B2446-0363-4720-AF46-F47F83B557DC} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{668F689E-57B4-422E-8846-C0FF643CA268} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{A9D039B9-7509-4CF1-9EFD-87EB82998575} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{D3804228-91F4-4502-9595-39584E5AADAD} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{5C09FB93-1535-4F92-AF26-21E8A061EE4A} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{B6269AAC-170A-4346-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{40BF24B5-12E6-4610-9489-138798632E28} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
@@ -351,6 +396,17 @@ Global
{B6269AAC-170A-4346-8B9A-579DED3D9A13} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE} = {0BB8B634-407A-4610-A91F-11586990767A}
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
{7753670F-7C7F-44BF-8BC7-08325588E60C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{E5B03EEF-822C-4295-952B-4479AD30082B} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{D3804228-91F4-4502-9595-39584E5A0177} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{BFEF8990-65B3-4274-310F-7355F0B84035} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{1F80A6E6-D146-4E40-9EA8-49DB8494239F} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{BBA332C6-28A9-42E7-9C4D-A0816E52A198} = {0BB8B634-407A-4610-A91F-11586990767A}
{B6269AAC-170A-4346-8B9A-444DED3D9A45} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{3FCBCA9C-9DB0-4A96-B47E-30470764CC9C} = {0BB8B634-407A-4610-A91F-11586990767A}
{1E874C8F-08A2-493B-8421-619F9A6E9E77} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{B47413AA-55D3-49A7-896A-17ADBFF72407} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

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

View File

@@ -1,181 +1,183 @@
variables:
Prerelease: 'ci'
buildId: "1$(Build.BuildId)"
buildProjects: '**/src/**/*.csproj'
jobs:
- job: Linux_Build_Test_SonarCloud
pool:
vmImage: 'Ubuntu-latest'
steps:
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
- task: CmdLine@2
displayName: 'Install .NET Aspire workload'
inputs:
script: 'dotnet workload install aspire'
- script: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
displayName: 'Install dotnet tools'
- task: PowerShell@2
displayName: "Use JDK17 by default"
inputs:
targetType: 'inline'
script: |
$jdkPath = $env:JAVA_HOME_17_X64
Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
- script: |
dotnet dev-certs https --trust || true
displayName: 'dotnet dev-certs https'
# See: https://docs.sonarsource.com/sonarcloud/enriching/test-coverage/dotnet-test-coverage
- script: |
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
displayName: 'Begin analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: '**/test/**/*.csproj'
arguments: '--configuration Debug --framework net8.0'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'WireMock.Net.Aspire.Tests with Coverage'
- task: CmdLine@2
displayName: 'Merge coverage files'
inputs:
script: 'dotnet coverage merge **/wiremock-coverage-*.xml --output ./test/wiremock-coverage.xml --output-format xml'
- script: |
dotnet sonarscanner end /d:sonar.token="$(SONAR_TOKEN)"
displayName: 'End analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- script: |
bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN) -f ./test/wiremock-coverage.xml
displayName: 'Upload coverage results to codecov'
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1
displayName: Publish coverage files
inputs:
PathtoPublish: './test/WireMock.Net.Tests/coverage.net8.0.opencover.xml'
- job: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release
projects: $(buildProjects)
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
variables:
Prerelease: 'ci'
buildId: "1$(Build.BuildId)"
buildProjects: '**/src/**/*.csproj'
jobs:
- job: Linux_Build_Test_SonarCloud
pool:
vmImage: 'ubuntu-22.04'
steps:
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
- script: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
displayName: 'Install dotnet tools'
- task: PowerShell@2
displayName: "Use JDK17 by default"
inputs:
targetType: 'inline'
script: |
$jdkPath = $env:JAVA_HOME_17_X64
Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
- script: |
dotnet dev-certs https --trust || true
displayName: 'dotnet dev-certs https'
# See: https://docs.sonarsource.com/sonarcloud/enriching/test-coverage/dotnet-test-coverage
- script: |
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
displayName: 'Begin analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: '**/test/**/*.csproj'
arguments: '--configuration Debug --framework net8.0'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'WireMock.Net.Aspire.Tests with Coverage'
- task: CmdLine@2
displayName: 'Merge coverage files'
inputs:
script: 'dotnet coverage merge **/wiremock-coverage-*.xml --output ./test/wiremock-coverage.xml --output-format xml'
- script: |
dotnet sonarscanner end /d:sonar.token="$(SONAR_TOKEN)"
displayName: 'End analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- script: |
bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN) -f ./test/wiremock-coverage.xml
displayName: 'Upload coverage results to codecov'
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1
displayName: Publish coverage files
inputs:
PathtoPublish: './test/WireMock.Net.Tests/coverage.net8.0.opencover.xml'
- job: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Tests.UsingNuGet'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests.UsingNuGet/WireMock.Net.Tests.UsingNuGet.csproj'
arguments: '--configuration Release'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release
projects: $(buildProjects)
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n -s https://www.myget.org/F/wiremock-net/api/v3/index.json -k $(MyGetKey)

View File

@@ -1,23 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,20 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" />
</ItemGroup>
</Project>

View File

@@ -2,22 +2,42 @@
using Greet;
using Grpc.Net.Client;
using Policy2;
namespace WireMock.Net.Console.GrpcClient;
await TestPolicyAsync();
// await TestGreeterAsync();
return;
internal class Program
async Task TestGreeterAsync()
{
static async Task Main(string[] args)
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc3", new GrpcChannelOptions
{
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc3", new GrpcChannelOptions
Credentials = Grpc.Core.ChannelCredentials.Insecure
});
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
Console.WriteLine("Greeting: " + reply.Message);
}
async Task TestPolicyAsync()
{
var channel = GrpcChannel.ForAddress("http://localhost:9093/grpc-policy", new GrpcChannelOptions
{
Credentials = Grpc.Core.ChannelCredentials.Insecure
});
var client = new PolicyService2.PolicyService2Client(channel);
var reply = await client.GetCancellationDetailAsync(new GetCancellationDetailRequest
{
Client = new Client
{
Credentials = Grpc.Core.ChannelCredentials.Insecure
});
CorrelationId = "abc"
}
});
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "stef" });
System.Console.WriteLine("Greeting: " + reply.Message);
}
Console.WriteLine("PolicyService2:reply.CancellationName " + reply.CancellationName);
}

View File

@@ -5,6 +5,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
@@ -18,6 +19,7 @@
<ItemGroup>
<Protobuf Include="greet.proto" GrpcServices="Client" />
<Protobuf Include="policy.proto" GrpcServices="Client" />
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,64 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
// option csharp_namespace = "NarrowIntegrationTest.Lookup";
package Policy2;
service PolicyService2 {
rpc GetCancellationDetail (GetCancellationDetailRequest) returns (GetCancellationDetailResponse);
}
message GetCancellationDetailRequest {
Client Client = 1;
LegacyPolicyKey LegacyPolicyKey = 2;
}
message GetCancellationDetailResponse {
ResponseStatus Status = 1;
string CancellationCode = 2;
string CancellationName = 3;
string CancellationDescription = 4;
google.protobuf.Timestamp CancellationEffDate = 5;
string NonRenewalCode = 6;
string NonRenewalName = 7;
string NonRenewalDescription = 8;
google.protobuf.Timestamp NonRenewalEffDate = 9;
google.protobuf.Timestamp LastReinstatementDate = 10;
}
message LegacyPolicyKey {
string Group = 1;
int32 UnitNumber = 2;
int32 Year = 3;
string Suffix = 4;
}
message ResponseStatus {
bool HasErrors = 1;
bool HasWarnings = 2;
repeated string Errors = 3;
repeated string Warnings = 4;
string CorrelationId = 5;
}
message Client {
string CorrelationId = 1;
enum Clients {
Unknown = 0;
QMS = 1;
BillingCenter = 2;
PAS = 3;
Payroll = 4;
Portal = 5;
SFO = 6;
QuoteAndBind = 7;
LegacyConversion = 8;
BindNow = 9;
PaymentPortal = 10 ;
PricingEngine = 11;
}
Clients ClientName = 2;
}

View File

@@ -6,11 +6,6 @@
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT;PROTOBUF</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net.Console.Net452.Classic\MainApp.cs" Link="MainApp.cs" />
<Compile Include="..\WireMock.Net.Console.Net452.Classic\CustomFileSystemFileHandler.cs" Link="CustomFileSystemFileHandler.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="__admin\mappings\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="HandlebarsDotNet.Helpers.Core" publicKeyToken="00d131fae0c250bc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.3.3.0" newVersion="2.3.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Handlebars" publicKeyToken="22225d0bf33cd661" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.2.0" newVersion="2.1.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

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

View File

@@ -1,37 +0,0 @@
// Copyright © WireMock.Net
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WireMock.Net.Console.Net452.Classic")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WireMock.Net.Console.Net452.Classic")]
[assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("668f689e-57b4-422e-8846-c0ff643ca268")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{668F689E-57B4-422E-8846-C0FF643CA268}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WireMock.Net.ConsoleApplication</RootNamespace>
<AssemblyName>WireMock.Net.ConsoleApplication</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>..\..\resources\WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AnyOf, Version=0.3.0.0, Culture=neutral, PublicKeyToken=b35e6abbb527c6b1, processorArchitecture=MSIL">
<HintPath>..\..\packages\AnyOf.0.3.0\lib\net45\AnyOf.dll</HintPath>
</Reference>
<Reference Include="Handlebars, Version=2.1.6.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.6\lib\net451\Handlebars.dll</HintPath>
</Reference>
<Reference Include="Handlebars.Net.Helpers, Version=2.4.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.4.3\lib\net452\Handlebars.Net.Helpers.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.4.3.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.4.3\lib\net452\HandlebarsDotNet.Helpers.Core.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=2.0.17.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.17\lib\net45\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.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>
</Reference>
<Reference Include="Stef.Validation, Version=0.1.1.0, Culture=neutral, PublicKeyToken=8f3400880c321038, processorArchitecture=MSIL">
<HintPath>..\..\packages\Stef.Validation.0.1.1\lib\net40\Stef.Validation.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="CustomFileSystemFileHandler.cs" />
<Compile Include="MainApp.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="__admin\mappings\873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj">
<Project>{b6269aac-170a-4346-8b9a-579ded3d9a94}</Project>
<Name>WireMock.Net.Abstractions</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj">
<Project>{d3804228-91f4-4502-9595-39584e5a01ad}</Project>
<Name>WireMock.Net</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="log4net">
<Version>2.0.17</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,21 +0,0 @@
{
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/static/mapping"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"BodyAsJson": { "body": "static mapping" },
"Headers": {
"Content-Type": "application/json"
}
}
}

View File

@@ -1,19 +0,0 @@
{
"Guid": "873d495f-940e-4b86-a1f4-4f0fc7be8b8b",
"Priority": 4,
"Request": {
"Path": {},
"Methods": [
"get"
]
},
"Response": {
"StatusCode": 200,
"BodyDestination": "SameAsSource",
"Body": "NO PATH OR URL",
"UseTransformer": false,
"Headers": {
"Content-Type": "application/json"
}
}
}

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{1} - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AnyOf" version="0.3.0" targetFramework="net452" />
<package id="Handlebars.Net" version="2.1.6" targetFramework="net452" />
<package id="Handlebars.Net.Helpers" version="2.4.3" targetFramework="net452" />
<package id="Handlebars.Net.Helpers.Core" version="2.4.3" targetFramework="net452" />
<package id="log4net" version="2.0.17" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net452" />
<package id="Stef.Validation" version="0.1.1" targetFramework="net452" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net452" />
</packages>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>

View File

@@ -1,60 +0,0 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Specialized;
using System.Net.Http;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.Proxy.Net452
{
class Program
{
static void Main(string[] args)
{
string[] urls = { "http://localhost:9091/", "https://localhost:9443/" };
var server = WireMockServer.Start(new WireMockServerSettings
{
Urls = urls,
StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "http://postman-echo.com/post",
//ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true,
SaveMappingToFile = false,
ExcludedHeaders = new[] { "dnt", "Content-Length" }
}
});
System.Console.WriteLine("Subscribing to LogEntriesChanged");
server.LogEntriesChanged += Server_LogEntriesChanged;
var uri = new Uri(urls[0]);
var form = new MultipartFormDataContent
{
{ new StringContent("data"), "test", "test.txt" }
};
new HttpClient().PostAsync(uri, form).GetAwaiter().GetResult();
System.Console.WriteLine("Unsubscribing to LogEntriesChanged");
server.LogEntriesChanged -= Server_LogEntriesChanged;
form = new MultipartFormDataContent
{
{ new StringContent("data2"), "test2", "test2.txt" }
};
new HttpClient().PostAsync(uri, form).GetAwaiter().GetResult();
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
}
private static void Server_LogEntriesChanged(object sender, NotifyCollectionChangedEventArgs eventRecordArgs)
{
System.Console.WriteLine("Server_LogEntriesChanged : {0}", eventRecordArgs.NewItems.Count);
}
}
}

View File

@@ -1,37 +0,0 @@
// Copyright © WireMock.Net
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WireMock.Net.Console.Proxy.Net452")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WireMock.Net.Console.Proxy.Net452")]
[assembly: AssemblyCopyright("Copyright © Stef Heyenrath 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("26433a8f-bf01-4962-97eb-81bffbb61096")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{26433A8F-BF01-4962-97EB-81BFFBB61096}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>WireMock.Net.Console.Proxy.Net452</RootNamespace>
<AssemblyName>WireMock.Net.Console.Proxy.Net452</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>WireMock.Net.Console.Proxy.Net452.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<None Condition="'$(Platform)' == 'x64'" Include="..\packages\Libuv.1.10.0\runtimes\win7-x64\native\libuv.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
<Link>libuv.dll</Link>
</None>
<None Condition="'$(Platform)' == 'x86'" Include="..\packages\Libuv.1.10.0\runtimes\win7-x86\native\libuv.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
<Link>libuv.dll</Link>
</None>
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj">
<Project>{d3804228-91f4-4502-9595-39584e5a01ad}</Project>
<Name>WireMock.Net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
</packages>

View File

@@ -0,0 +1,88 @@
// Copyright © WireMock.Net
using System.Net.Http.Headers;
using System.Text;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
Directory.SetCurrentDirectory(Path.GetTempPath());
using var server = WireMockServer.Start();
var textPlainContent = "This is some plain text";
var textPlainContentType = "text/plain";
var textPlainContentTypeMatcher = new ContentTypeMatcher(textPlainContentType);
var textPlainContentMatcher = new ExactMatcher(textPlainContent);
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
var textJson = "{ \"Key\" : \"Value\" }";
var textJsonContentType = "text/json";
var textJsonContentTypeMatcher = new ContentTypeMatcher(textJsonContentType);
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
var jsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);
var imagePngBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC");
var imagePngContentMatcher = new ExactObjectMatcher(imagePngBytes);
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, imagePngContentMatcher);
var matchers = new IMatcher[]
{
textPlainMatcher,
jsonMatcher,
imagePngMatcher
};
server
.Given(Request.Create()
.UsingPost()
.WithPath("/multipart")
.WithMultiPart(matchers)
)
.RespondWith(Response.Create()
.WithBodyAsJson(new
{
Method = "{{request.Method}}",
BodyAsMimeMessage = "{{request.BodyAsMimeMessage.TextBody}}"
})
.WithTransformer()
);
server
.Given(Request.Create()
.UsingPost()
.WithPath("/multipart2")
.WithMultiPart(matchers)
)
.RespondWith(Response.Create()
.WithBody(request =>
{
if (request.BodyAsMimeMessage == null)
{
throw new InvalidProgramException("Not expected");
}
return "OK";
})
.WithTransformer()
);
var formDataContent = new MultipartFormDataContent
{
{ new StringContent(textPlainContent, Encoding.UTF8, textPlainContentType), "text" },
{ new StringContent(textJson, Encoding.UTF8, textJsonContentType), "json" }
};
var fileContent = new ByteArrayContent(imagePngBytes);
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
formDataContent.Add(fileContent, "somefile", "image.png");
var client = server.CreateClient();
var response = await client.PostAsync("/multipart", formDataContent);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
var response2 = await client.PostAsync("/multipart2", formDataContent);
var content2 = await response2.Content.ReadAsStringAsync();
Console.WriteLine(content2);

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="SonarAnalyzer.CSharp" Version="10.12.0.118525" />
</ItemGroup>
<!--<ItemGroup>
<PackageReference Include="WireMock.Net" Version="1.8.11" />
</ItemGroup>-->
</Project>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@@ -113,20 +113,13 @@
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj">
<Project>{b6269aac-170a-4346-8b9a-579ded3d9a94}</Project>
<Name>WireMock.Net.Abstractions</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj">
<Project>{d3804228-91f4-4502-9595-39584e5a01ad}</Project>
<Name>WireMock.Net</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="log4net">
<Version>3.0.3</Version>
</PackageReference>
<PackageReference Include="WireMock.Net">
<Version>1.8.11</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -159,9 +159,7 @@ internal class Program
private static async Task TestWindowsCopyAsync()
{
var builder = new WireMockContainerBuilder()
.WithWatchStaticMappings(true)
.WithAutoRemove(true)
.WithCleanUp(true);
.WithWatchStaticMappings(true);
var container = builder.Build();
@@ -186,8 +184,6 @@ internal class Program
var mappings = await adminClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
await Task.Delay(1_000);
await container.StopAsync();
}
@@ -205,9 +201,7 @@ internal class Program
.WithNetwork(dummyNetwork)
.WithAdminUserNameAndPassword("x", "y")
.WithMappings(mappingsPath)
.WithWatchStaticMappings(true)
// .WithAutoRemove(true)
.WithCleanUp(true);
.WithWatchStaticMappings(true);
if (image != null)
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 12 KiB

BIN
resources/logo_32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -56,6 +56,11 @@ public class MappingModel
/// In case the value is null state will not be changed.
/// </summary>
public string? SetStateTo { get; set; }
/// <summary>
/// The number of times this match should be matched before the state will be changed to the specified one.
/// </summary>
public int? TimesInSameState { get; set; }
/// <summary>
/// The request model.
@@ -86,7 +91,7 @@ public class MappingModel
/// Fire and forget for webhooks.
/// </summary>
public bool? UseWebhooksFireAndForget { get; set; }
/// <summary>
/// Data Object which can be used when WithTransformer is used.
/// e.g. lookup a path in this object using

View File

@@ -0,0 +1,15 @@
// Copyright © WireMock.Net
namespace WireMock.Admin.Scenarios;
/// <summary>
/// ScenarioStateModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class ScenarioStateUpdateModel
{
/// <summary>
/// Gets or sets the NextState.
/// </summary>
public string? State { get; set; }
}

View File

@@ -138,4 +138,27 @@ public partial class RequestModelBuilder
return builder.Build();
});
}
/// <summary>
/// WithHeader: matching based on name, pattern and matchBehaviour.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="rejectOnMatch">The match behaviour. Default value is <c>false</c>.</param>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder WithHeader(string name, string pattern, bool rejectOnMatch = false)
{
return WithHeaders(headersBuilder => headersBuilder
.Add(headerBuilder => headerBuilder
.WithName(name)
.WithMatchers(matchersBuilder => matchersBuilder
.Add(matcherBuilder => matcherBuilder
.WithName("WildcardMatcher")
.WithPattern(pattern)
.WithRejectOnMatch(rejectOnMatch)
)
)
)
);
}
}

View File

@@ -123,7 +123,7 @@ public interface IRequestMessage
/// The original body as MimeMessage.
/// Convenience getter for Handlebars and WireMockAssertions.
/// </summary>
object? BodyAsMimeMessage { get; }
Models.Mime.IMimeMessageData? BodyAsMimeMessage { get; }
#endif
/// <summary>

View File

@@ -15,12 +15,12 @@ public interface IResponseMessage
/// <summary>
/// The Body.
/// </summary>
IBodyData? BodyData { get; }
IBodyData? BodyData { get; set; }
/// <summary>
/// Gets the body destination (Null, SameAsSource, String or Bytes).
/// </summary>
string? BodyDestination { get; }
string? BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
@@ -30,27 +30,27 @@ public interface IResponseMessage
/// <summary>
/// Gets the Fault percentage.
/// </summary>
double? FaultPercentage { get; }
double? FaultPercentage { get; set; }
/// <summary>
/// The FaultType.
/// </summary>
FaultType FaultType { get; }
FaultType FaultType { get; set; }
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>>? Headers { get; }
IDictionary<string, WireMockList<string>>? Headers { get; set; }
/// <summary>
/// Gets the trailing headers.
/// </summary>
IDictionary<string, WireMockList<string>>? TrailingHeaders { get; }
IDictionary<string, WireMockList<string>>? TrailingHeaders { get; set; }
/// <summary>
/// Gets or sets the status code.
/// </summary>
object? StatusCode { get; }
object? StatusCode { get; set; }
/// <summary>
/// Adds the header.

View File

@@ -0,0 +1,5 @@
// Copyright © WireMock.Net
namespace WireMock.Models.GraphQL;
public interface ISchemaData;

View File

@@ -0,0 +1,30 @@
// Copyright © WireMock.Net
using System.Diagnostics.CodeAnalysis;
namespace WireMock.Models;
/// <summary>
/// A simple implementation for a Blocking Queue.
/// </summary>
/// <typeparam name="T">Specifies the type of elements in the queue.</typeparam>
public interface IBlockingQueue<T>
{
/// <summary>
/// Writes an item to the queue and signals that an item is available.
/// </summary>
/// <param name="item">The item to be added to the queue.</param>
void Write(T item);
/// <summary>
/// Tries to read an item from the queue. Waits until an item is available or the timeout occurs.
/// </summary>
/// <param name="item">The item read from the queue, or default if the timeout occurs.</param>
/// <returns>True if an item was successfully read; otherwise, false.</returns>
bool TryRead([NotNullWhen(true)] out T? item);
/// <summary>
/// Closes the queue and signals all waiting threads.
/// </summary>
public void Close();
}

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using WireMock.Models;
using WireMock.Types;
@@ -71,7 +72,7 @@ public interface IBodyData
Encoding? Encoding { get; set; }
/// <summary>
/// Defines if this BodyData is the result of a dynamically created response-string. (
/// Defines if this BodyData is the result of a dynamically created response-string.
/// </summary>
public string? IsFuncUsed { get; set; }
@@ -86,4 +87,14 @@ public interface IBodyData
/// </summary>
public string? ProtoBufMessageType { get; set; }
#endregion
/// <summary>
/// Defines the queue to use for Server-Sent Events (string).
/// </summary>
public IBlockingQueue<string?>? SseStringQueue { get; set; }
/// <summary>
/// Defines if the body is using Server-Sent Events (string).
/// </summary>
public Task? BodyAsSseStringTask { get; set; }
}

View File

@@ -8,18 +8,8 @@ namespace WireMock.Util;
// ReSharper disable once InconsistentNaming
public static class IBodyDataExtensions
{
public static BodyType GetBodyType(this IBodyData bodyData)
public static BodyType GetDetectedBodyType(this IBodyData bodyData)
{
if (bodyData.DetectedBodyTypeFromContentType is not null and not BodyType.None)
{
return bodyData.DetectedBodyTypeFromContentType.Value;
}
if (bodyData.DetectedBodyType is not null and not BodyType.None)
{
return bodyData.DetectedBodyType.Value;
}
return BodyType.None;
return bodyData.DetectedBodyType ?? BodyType.None;
}
}

View File

@@ -0,0 +1,60 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
namespace WireMock.Models.Mime;
/// <summary>
/// An interface exposing the public, readable properties of a ContentDisposition.
/// </summary>
public interface IContentDispositionData
{
/// <summary>
/// Get the disposition.
/// </summary>
/// <value>The disposition.</value>
string Disposition { get; }
/// <summary>
/// Get a value indicating whether the <see cref="IMimeEntityData"/> is an attachment.
/// </summary>
/// <value><see langword="true" /> if the <see cref="IMimeEntityData"/> is an attachment; otherwise, <see langword="false" />.</value>
bool IsAttachment { get; }
/// <summary>
/// Get the list of parameters on the ContentDisposition.
/// </summary>
/// <value>The parameters.</value>
public IList<string> Parameters { get; }
/// <summary>
/// Get the name of the file.
/// </summary>
/// <value>The name of the file.</value>
string FileName { get; }
/// <summary>
/// Get the creation-date parameter.
/// </summary>
/// <value>The creation date.</value>
DateTimeOffset? CreationDate { get; }
/// <summary>
/// Get the modification-date parameter.
/// </summary>
/// <value>The modification date.</value>
DateTimeOffset? ModificationDate { get; }
/// <summary>
/// Get the read-date parameter.
/// </summary>
/// <value>The read date.</value>
DateTimeOffset? ReadDate { get; }
/// <summary>
/// Get the size parameter.
/// </summary>
/// <value>The size.</value>
long? Size { get; }
}

View File

@@ -0,0 +1,67 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.Text;
namespace WireMock.Models.Mime;
/// <summary>
/// An interface exposing the public, readable properties of a ContentType
/// with complex types simplified to a generic object.
/// </summary>
public interface IContentTypeData
{
/// <summary>
/// Get the type of the media.
/// </summary>
/// <value>The type of the media.</value>
string MediaType { get; }
/// <summary>
/// Get the media subtype.
/// </summary>
/// <value>The media subtype.</value>
string MediaSubtype { get; }
/// <summary>
/// Get the list of parameters on the ContentType.
/// </summary>
/// <value>The parameters.</value>
IList<string> Parameters { get; }
/// <summary>
/// Get the boundary parameter.
/// </summary>
/// <value>The boundary.</value>
string Boundary { get; }
/// <summary>
/// Get the charset parameter.
/// </summary>
/// <value>The charset.</value>
string Charset { get; }
/// <summary>
/// Get the charset parameter as an Encoding.
/// </summary>
/// <value>The charset encoding.</value>
Encoding CharsetEncoding { get; }
/// <summary>
/// Get the format parameter.
/// </summary>
/// <value>The format.</value>
string Format { get; }
/// <summary>
/// Get the simple mime-type.
/// </summary>
/// <value>The mime-type.</value>
string MimeType { get; }
/// <summary>
/// Get the name parameter.
/// </summary>
/// <value>The name.</value>
string Name { get; }
}

View File

@@ -0,0 +1,54 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
namespace WireMock.Models.Mime;
/// <summary>
/// A simplified interface exposing the public, readable properties of MimeEntity.
/// </summary>
public interface IMimeEntityData
{
/// <summary>
/// Get the list of headers.
/// </summary>
/// <value>The list of headers.</value>
IList<string> Headers { get; }
/// <summary>
/// Get the content disposition.
/// </summary>
/// <value>The content disposition.</value>
IContentDispositionData? ContentDisposition { get; }
/// <summary>
/// Get the type of the content.
/// </summary>
/// <value>The type of the content.</value>
IContentTypeData? ContentType { get; }
/// <summary>
/// Get the base content URI.
/// </summary>
/// <value>The base content URI or <see langword="null"/>.</value>
Uri ContentBase { get; }
/// <summary>
/// Get the content location.
/// </summary>
/// <value>The content location or <see langword="null"/>.</value>
Uri ContentLocation { get; }
/// <summary>
/// Get the Content-Id.
/// </summary>
/// <value>The content identifier.</value>
string ContentId { get; }
/// <summary>
/// Get a value indicating whether this <see cref="IMimeEntityData"/> is an attachment.
/// </summary>
/// <value><see langword="true" /> if this <see cref="IMimeEntityData"/> is an attachment; otherwise, <see langword="false" />.</value>
bool IsAttachment { get; }
}

View File

@@ -0,0 +1,186 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
namespace WireMock.Models.Mime;
/// <summary>
/// A simplified interface exposing the public, readable properties of a MIME message.
/// </summary>
public interface IMimeMessageData
{
/// <summary>
/// Get the list of headers.
/// </summary>
/// <value>The list of headers.</value>
IList<string> Headers { get; }
/// <summary>
/// Get the value of the Importance header.
/// </summary>
/// <value>The importance, as an integer.</value>
int Importance { get; }
/// <summary>
/// Get the value of the Priority header.
/// </summary>
/// <value>The priority, as an integer.</value>
int Priority { get; }
/// <summary>
/// Get the value of the X-Priority header.
/// </summary>
/// <value>The X-priority, as an integer.</value>
int XPriority { get; }
/// <summary>
/// Get the address in the Sender header.
/// </summary>
/// <value>The address in the Sender header.</value>
string Sender { get; }
/// <summary>
/// Get the address in the Resent-Sender header.
/// </summary>
/// <value>The address in the Resent-Sender header.</value>
string ResentSender { get; }
/// <summary>
/// Get the list of addresses in the From header.
/// </summary>
/// <value>The list of addresses in the From header.</value>
IList<string> From { get; }
/// <summary>
/// Get the list of addresses in the Resent-From header.
/// </summary>
/// <value>The list of addresses in the Resent-From header.</value>
IList<string> ResentFrom { get; }
/// <summary>
/// Get the list of addresses in the Reply-To header.
/// </summary>
/// <value>The list of addresses in the Reply-To header.</value>
IList<string> ReplyTo { get; }
/// <summary>
/// Get the list of addresses in the Resent-Reply-To header.
/// </summary>
/// <value>The list of addresses in the Resent-Reply-To header.</value>
IList<string> ResentReplyTo { get; }
/// <summary>
/// Get the list of addresses in the To header.
/// </summary>
/// <value>The list of addresses in the To header.</value>
IList<string> To { get; }
/// <summary>
/// Get the list of addresses in the Resent-To header.
/// </summary>
/// <value>The list of addresses in the Resent-To header.</value>
IList<string> ResentTo { get; }
/// <summary>
/// Get the list of addresses in the Cc header.
/// </summary>
/// <value>The list of addresses in the Cc header.</value>
IList<string> Cc { get; }
/// <summary>
/// Get the list of addresses in the Resent-Cc header.
/// </summary>
/// <value>The list of addresses in the Resent-Cc header.</value>
IList<string> ResentCc { get; }
/// <summary>
/// Get the list of addresses in the Bcc header.
/// </summary>
/// <value>The list of addresses in the Bcc header.</value>
IList<string> Bcc { get; }
/// <summary>
/// Get the list of addresses in the Resent-Bcc header.
/// </summary>
/// <value>The list of addresses in the Resent-Bcc header.</value>
IList<string> ResentBcc { get; }
/// <summary>
/// Get the subject of the message.
/// </summary>
/// <value>The subject of the message.</value>
string Subject { get; }
/// <summary>
/// Get the date of the message.
/// </summary>
/// <value>The date of the message.</value>
DateTimeOffset Date { get; }
/// <summary>
/// Get the Resent-Date of the message.
/// </summary>
/// <value>The Resent-Date of the message.</value>
DateTimeOffset ResentDate { get; }
/// <summary>
/// Get the list of references to other messages.
/// </summary>
/// <value>The references.</value>
IList<string> References { get; }
/// <summary>
/// Get the Message-Id that this message is replying to.
/// </summary>
/// <value>The message id that this message is in reply to.</value>
string InReplyTo { get; }
/// <summary>
/// Get the message identifier.
/// </summary>
/// <value>The message identifier.</value>
string MessageId { get; }
/// <summary>
/// Get the Resent-Message-Id header.
/// </summary>
/// <value>The Resent-Message-Id.</value>
string ResentMessageId { get; }
/// <summary>
/// Get the MIME-Version.
/// </summary>
/// <value>The MIME version.</value>
Version MimeVersion { get; }
/// <summary>
/// Get the body of the message.
/// </summary>
/// <value>The body of the message.</value>
IMimeEntityData Body { get; }
/// <summary>
/// Get the text body of the message if it exists.
/// </summary>
/// <value>The text body if it exists; otherwise, <see langword="null"/>.</value>
string TextBody { get; }
/// <summary>
/// Get the html body of the message if it exists.
/// </summary>
/// <value>The html body if it exists; otherwise, <see langword="null"/>.</value>
string HtmlBody { get; }
/// <summary>
/// Get the body parts of the message.
/// </summary>
/// <value>The body parts.</value>
IList<IMimePartData> BodyParts { get; }
/// <summary>
/// Get the attachments.
/// </summary>
/// <value>The attachments.</value>
IList<IMimeEntityData> Attachments { get; }
}

View File

@@ -0,0 +1,57 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.IO;
namespace WireMock.Models.Mime;
/// <summary>
/// A simplified interface exposing the public, readable properties of MimePart.
/// </summary>
public interface IMimePartData : IMimeEntityData
{
/// <summary>
/// Get the description of the content if available.
/// </summary>
/// <value>The description of the content.</value>
string ContentDescription { get; }
/// <summary>
/// Get the duration of the content if available.
/// </summary>
/// <value>The duration of the content.</value>
int? ContentDuration { get; }
/// <summary>
/// Get the md5sum of the content.
/// </summary>
/// <value>The md5sum of the content.</value>
string ContentMd5 { get; }
/// <summary>
/// Get the content transfer encoding.
/// </summary>
/// <value>The content transfer encoding as a string.</value>
string ContentTransferEncoding { get; }
/// <summary>
/// Get the name of the file.
/// </summary>
/// <value>The name of the file.</value>
string FileName { get; }
/// <summary>
/// Get the MIME content.
/// </summary>
/// <value>The MIME content.</value>
IDictionary<string, object?> Content { get; }
/// <summary>
/// Open the decoded content stream.
/// </summary>
/// <remarks>
/// Provides a means of reading the decoded content without having to first write it to another stream.
/// </remarks>
/// <returns>The decoded content stream.</returns>
Stream Open();
}

View File

@@ -0,0 +1,8 @@
// Copyright © WireMock.Net
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
// Needed for Moq in the UnitTest project
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@@ -161,6 +161,11 @@ public interface IWireMockServer : IDisposable
/// </summary>
bool ResetScenario(string name);
/// <summary>
/// Sets a scenario to a state.
/// </summary>
bool SetScenarioState(string name, string? state);
/// <summary>
/// Resets the LogEntries.
/// </summary>

View File

@@ -45,5 +45,10 @@ public enum BodyType
/// <summary>
/// Body is a ProtoBuf Byte array
/// </summary>
ProtoBuf
ProtoBuf,
/// <summary>
/// Use Server-Sent Events (string)
/// </summary>
SseString
}

View File

@@ -0,0 +1,16 @@
using System;
namespace WireMock.Types;
/// <summary>
/// A enum defining the supported Handlebar helpers.
/// </summary>
[Flags]
public enum CustomHandlebarsHelpers
{
None = 0,
File = 1,
All = File
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Commonly used models, enumerations and types.</Description>
<Description>Commonly used interfaces, models, enumerations and types.</Description>
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;net451;net461;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
@@ -17,7 +17,6 @@
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
@@ -25,6 +24,10 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<!--<PathMap>$(MSBuildProjectDirectory)=/</PathMap>-->
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@@ -35,30 +38,27 @@
</PropertyGroup>
<ItemGroup>
<!-- CVE-2018-8292 / https://github.com/advisories/GHSA-7jgj-8wvc-jh57 -->
<PackageReference Include="System.Net.Http " Version="4.3.4" />
<!-- See also https://mstack.nl/blog/20210801-source-generators -->
<PackageReference Include="FluentBuilder" Version="0.10.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="PolySharp" Version="1.15.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- CVE-2018-8292 -->
<PackageReference Include="System.Net.Http " Version="4.3.4" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetFramework)' != 'netstandard1.0'">
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net46" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net461'">
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
</Project>

View File

@@ -36,7 +36,6 @@ internal class WireMockDelegationHandler : DelegatingHandler
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Guard.NotNull(request);
Guard.NotNull(_httpContextAccessor.HttpContext);
if (_settings.AlwaysRedirect || IsWireMockRedirectHeaderSetToTrue())
{
@@ -57,16 +56,30 @@ internal class WireMockDelegationHandler : DelegatingHandler
private bool IsWireMockRedirectHeaderSetToTrue()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext is null)
{
_logger.LogDebug("HttpContext is not available in current runtime environment");
return false;
}
return
_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_REDIRECT, out var values) &&
httpContext.Request.Headers.TryGetValue(AppConstants.HEADER_REDIRECT, out var values) &&
bool.TryParse(values.ToString(), out var shouldRedirectToWireMock) && shouldRedirectToWireMock;
}
private bool TryGetDelayHeaderValue(out int delayInMs)
{
delayInMs = 0;
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext is null)
{
_logger.LogDebug("HttpContext is not available in current runtime environment");
return false;
}
return
_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue(AppConstants.HEADER_RESPONSE_DELAY, out var values) &&
httpContext.Request.Headers.TryGetValue(AppConstants.HEADER_RESPONSE_DELAY, out var values) &&
int.TryParse(values.ToString(), out delayInMs);
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -16,7 +16,6 @@
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
@@ -25,6 +24,10 @@
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
@@ -39,7 +42,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
<ProjectReference Include="..\WireMock.Net.Minimal\WireMock.Net.Minimal.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,49 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Aspire</AssemblyName>
<PackageId>WireMock.Net.Aspire</PackageId>
<PackageTags>dotnet;aspire;wiremock;extension</PackageTags>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A12}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="../../resources/WireMock.Net-Logo.png" />
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="8.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Aspire</AssemblyName>
<PackageId>WireMock.Net.Aspire</PackageId>
<PackageTags>dotnet;aspire;wiremock;extension</PackageTags>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A12}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="../../resources/WireMock.Net-Logo.png" />
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net.Minimal\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="9.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,49 @@
// Copyright © WireMock.Net
using System.Diagnostics;
using System.Runtime.CompilerServices;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting.WireMock;
internal static class WireMockInspector
{
/// <summary>
/// Opens the WireMockInspector tool to inspect the WireMock server.
/// </summary>
/// <param name="wireMockUrl"></param>
/// <param name="title"></param>
/// <exception cref="InvalidOperationException"></exception>
/// <remarks>
/// Copy of <see href="https://github.com/WireMock-Net/WireMockInspector/blob/main/src/WireMock.Net.Extensions.WireMockInspector/WireMockServerExtensions.cs" />
/// without requestFilters and no call to WaitForExit() method in the process so it doesn't block the caller.
/// </remarks>
public static void Inspect(string wireMockUrl, [CallerMemberName] string title = "")
{
try
{
var arguments = $"attach --adminUrl {wireMockUrl} --autoLoad --instanceName \"{title}\"";
Process.Start(new ProcessStartInfo
{
FileName = "wiremockinspector",
Arguments = arguments,
UseShellExecute = false
});
}
catch (Exception e)
{
throw new InvalidOperationException
(
message:
"""
Cannot find installation of WireMockInspector.
Execute the following command to install WireMockInspector dotnet tool:
> dotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources
To get more info please visit https://github.com/WireMock-Net/WireMockInspector
""",
innerException: e
);
}
}
}

View File

@@ -1,175 +1,222 @@
// Copyright © WireMock.Net
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Stef.Validation;
using WireMock.Client.Builders;
using WireMock.Net.Aspire;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting;
/// <summary>
/// Provides extension methods for adding WireMock.Net Server resources to the application model.
/// </summary>
public static class WireMockServerBuilderExtensions
{
// Linux only (https://github.com/dotnet/aspire/issues/854)
private const string DefaultLinuxImage = "sheyenrath/wiremock.net-alpine";
private const string DefaultLinuxMappingsPath = "/app/__admin/mappings";
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="port">The HTTP port for the WireMock Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, int? port = null)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.Condition(port, p => p is null or > 0 and <= ushort.MaxValue);
return builder.AddWireMock(name, callback =>
{
callback.HttpPort = port;
});
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, WireMockServerArguments arguments)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(arguments);
var wireMockContainerResource = new WireMockServerResource(name, arguments);
var resourceBuilder = builder
.AddResource(wireMockContainerResource)
.WithImage(DefaultLinuxImage)
.WithEnvironment(ctx => ctx.EnvironmentVariables.Add("DOTNET_USE_POLLING_FILE_WATCHER", "1")) // https://khalidabuhakmeh.com/aspnet-docker-gotchas-and-workarounds#configuration-reloads-and-filesystemwatcher
.WithHttpEndpoint(port: arguments.HttpPort, targetPort: WireMockServerArguments.HttpContainerPort);
if (!string.IsNullOrEmpty(arguments.MappingsPath))
{
resourceBuilder = resourceBuilder.WithBindMount(arguments.MappingsPath, DefaultLinuxMappingsPath);
}
resourceBuilder = resourceBuilder.WithArgs(ctx =>
{
foreach (var arg in arguments.GetArgs())
{
ctx.Args.Add(arg);
}
});
return resourceBuilder;
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="callback">A callback that allows for setting the <see cref="WireMockServerArguments"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, Action<WireMockServerArguments> callback)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(callback);
var arguments = new WireMockServerArguments();
callback(arguments);
return builder.AddWireMock(name, arguments);
}
/// <summary>
/// Defines if the static mappings should be read at startup.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.ReadStaticMappings = true;
return wiremock;
}
/// <summary>
/// Watch the static mapping files + folder for changes when running.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}
/// <summary>
/// Specifies the path for the (static) mapping json files.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="mappingsPath">The local path.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;
return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}
/// <summary>
/// Set the admin username and password for accessing the admin interface from WireMock.Net via HTTP.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="username">The admin username.</param>
/// <param name="password">The admin password.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassword(this IResourceBuilder<WireMockServerResource> wiremock, string username, string password)
{
Guard.NotNull(wiremock);
wiremock.Resource.Arguments.AdminUsername = Guard.NotNull(username);
wiremock.Resource.Arguments.AdminPassword = Guard.NotNull(password);
return wiremock;
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);
wiremock.ApplicationBuilder.Services.TryAddLifecycleHook<WireMockServerLifecycleHook>();
wiremock.Resource.Arguments.ApiMappingBuilder = configure;
return wiremock;
}
// Copyright © WireMock.Net
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Aspire.Hosting.WireMock;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Stef.Validation;
using WireMock.Client.Builders;
using WireMock.Net.Aspire;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting;
/// <summary>
/// Provides extension methods for adding WireMock.Net Server resources to the application model.
/// </summary>
public static class WireMockServerBuilderExtensions
{
// Linux only (https://github.com/dotnet/aspire/issues/854)
private const string DefaultLinuxImage = "sheyenrath/wiremock.net-alpine";
private const string DefaultLinuxMappingsPath = "/app/__admin/mappings";
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="port">The HTTP port for the WireMock Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, int? port = null)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.Condition(port, p => p is null or > 0 and <= ushort.MaxValue);
return builder.AddWireMock(name, callback =>
{
callback.HttpPort = port;
});
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, WireMockServerArguments arguments)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(arguments);
var wireMockContainerResource = new WireMockServerResource(name, arguments);
var resourceBuilder = builder
.AddResource(wireMockContainerResource)
.WithImage(DefaultLinuxImage)
.WithEnvironment(ctx => ctx.EnvironmentVariables.Add("DOTNET_USE_POLLING_FILE_WATCHER", "1")) // https://khalidabuhakmeh.com/aspnet-docker-gotchas-and-workarounds#configuration-reloads-and-filesystemwatcher
.WithHttpEndpoint(port: arguments.HttpPort, targetPort: WireMockServerArguments.HttpContainerPort)
.WithWireMockInspectorCommand();
if (!string.IsNullOrEmpty(arguments.MappingsPath))
{
resourceBuilder = resourceBuilder.WithBindMount(arguments.MappingsPath, DefaultLinuxMappingsPath);
}
resourceBuilder = resourceBuilder.WithArgs(ctx =>
{
foreach (var arg in arguments.GetArgs())
{
ctx.Args.Add(arg);
}
});
return resourceBuilder;
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="callback">A callback that allows for setting the <see cref="WireMockServerArguments"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, Action<WireMockServerArguments> callback)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(callback);
var arguments = new WireMockServerArguments();
callback(arguments);
return builder.AddWireMock(name, arguments);
}
/// <summary>
/// Defines if the static mappings should be read at startup.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.ReadStaticMappings = true;
return wiremock;
}
/// <summary>
/// Watch the static mapping files + folder for changes when running.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}
/// <summary>
/// Specifies the path for the (static) mapping json files.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="mappingsPath">The local path.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;
return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}
/// <summary>
/// Set the admin username and password for accessing the admin interface from WireMock.Net via HTTP.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="username">The admin username.</param>
/// <param name="password">The admin password.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassword(this IResourceBuilder<WireMockServerResource> wiremock, string username, string password)
{
Guard.NotNull(wiremock);
wiremock.Resource.Arguments.AdminUsername = Guard.NotNull(username);
wiremock.Resource.Arguments.AdminPassword = Guard.NotNull(password);
return wiremock;
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);
wiremock.ApplicationBuilder.Services.TryAddLifecycleHook<WireMockServerLifecycleHook>();
wiremock.Resource.Arguments.ApiMappingBuilder = configure;
return wiremock;
}
/// <summary>
/// Enables the WireMockInspect, a cross-platform UI app that facilitates WireMock troubleshooting.
/// This requires installation of the WireMockInspector tool.
/// <code>
/// dotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources
/// </code>
/// </summary>
/// <param name="builder">The <see cref="IResourceBuilder{WireMockNetResource}"/>.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithWireMockInspectorCommand(this IResourceBuilder<WireMockServerResource> builder)
{
Guard.NotNull(builder);
CommandOptions commandOptions = new()
{
Description = "Requires installation of the WireMockInspector (https://github.com/WireMock-Net/WireMockInspector) tool:\ndotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources",
UpdateState = OnUpdateResourceState,
IconName = "BoxSearch",
IconVariant = IconVariant.Filled
};
builder.WithCommand(
name: "wiremock-inspector",
displayName: "WireMock Inspector",
executeCommand: _ => OnRunOpenInspectorCommandAsync(builder),
commandOptions: commandOptions);
return builder;
}
private static Task<ExecuteCommandResult> OnRunOpenInspectorCommandAsync(IResourceBuilder<WireMockServerResource> builder)
{
WireMockInspector.Inspect(builder.Resource.GetEndpoint().Url);
return Task.FromResult(CommandResults.Success());
}
private static ResourceCommandState OnUpdateResourceState(UpdateCommandStateContext context)
{
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
}

View File

@@ -0,0 +1,40 @@
// Copyright © WireMock.Net
using Stef.Validation;
using WireMock.Server;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
/// <summary>
/// Provides assertion methods to verify the number of calls made to a WireMock server.
/// This class is used in the context of AwesomeAssertions.
/// </summary>
public class WireMockANumberOfCallsAssertions
{
private readonly IWireMockServer _server;
private readonly int _callsCount;
private readonly AssertionChain _chain;
/// <summary>
/// Initializes a new instance of the <see cref="WireMockANumberOfCallsAssertions"/> class.
/// </summary>
/// <param name="server">The WireMock server to assert against.</param>
/// <param name="callsCount">The expected number of calls to assert.</param>
/// <param name="chain">The assertion chain</param>
public WireMockANumberOfCallsAssertions(IWireMockServer server, int callsCount, AssertionChain chain)
{
_server = Guard.NotNull(server);
_callsCount = callsCount;
_chain = chain;
}
/// <summary>
/// Returns an instance of <see cref="WireMockAssertions"/> which can be used to assert the expected number of calls.
/// </summary>
/// <returns>A <see cref="WireMockAssertions"/> instance for asserting the number of calls to the server.</returns>
public WireMockAssertions Calls()
{
return new WireMockAssertions(_server, _callsCount, _chain);
}
}

View File

@@ -0,0 +1,83 @@
// Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Matchers;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
#pragma warning disable CS1591
public partial class WireMockAssertions
{
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtAbsolutePath(string absolutePath, string because = "", params object[] becauseArgs)
{
_ = AtAbsolutePath(new ExactMatcher(true, absolutePath), because, becauseArgs);
return new AndWhichConstraint<WireMockAssertions, string>(this, absolutePath);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtAbsolutePath(IStringMatcher absolutePathMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => absolutePathMatcher.IsPerfectMatch(request.AbsolutePath));
var absolutePath = absolutePathMatcher.GetPatterns().FirstOrDefault().GetPattern();
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute path {0}{reason}, but no calls were made.",
absolutePath
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute path {0}{reason}, but didn't find it among the calls to {1}.",
_ => absolutePath,
requests => requests.Select(request => request.AbsolutePath)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, absolutePathMatcher);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtPath(string path, string because = "", params object[] becauseArgs)
{
_ = AtPath(new ExactMatcher(true, path), because, becauseArgs);
return new AndWhichConstraint<WireMockAssertions, string>(this, path);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtPath(IStringMatcher pathMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => pathMatcher.IsPerfectMatch(request.Path));
var path = pathMatcher.GetPatterns().FirstOrDefault().GetPattern();
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the path {0}{reason}, but no calls were made.",
path
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the path {0}{reason}, but didn't find it among the calls to {1}.",
_ => path,
requests => requests.Select(request => request.Path)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, pathMatcher);
}
}

View File

@@ -0,0 +1,83 @@
// Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Matchers;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
#pragma warning disable CS1591
public partial class WireMockAssertions
{
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs)
{
_ = AtAbsoluteUrl(new ExactMatcher(true, absoluteUrl), because, becauseArgs);
return new AndWhichConstraint<WireMockAssertions, string>(this, absoluteUrl);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtAbsoluteUrl(IStringMatcher absoluteUrlMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => absoluteUrlMatcher.IsPerfectMatch(request.AbsoluteUrl));
var absoluteUrl = absoluteUrlMatcher.GetPatterns().FirstOrDefault().GetPattern();
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but no calls were made.",
absoluteUrl
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but didn't find it among the calls to {1}.",
_ => absoluteUrl,
requests => requests.Select(request => request.AbsoluteUrl)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, absoluteUrlMatcher);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtUrl(string url, string because = "", params object[] becauseArgs)
{
_ = AtUrl(new ExactMatcher(true, url), because, becauseArgs);
return new AndWhichConstraint<WireMockAssertions, string>(this, url);
}
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtUrl(IStringMatcher urlMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => urlMatcher.IsPerfectMatch(request.Url));
var url = urlMatcher.GetPatterns().FirstOrDefault().GetPattern();
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but no calls were made.",
url
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but didn't find it among the calls to {1}.",
_ => url,
requests => requests.Select(request => request.Url)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, urlMatcher);
}
}

View File

@@ -0,0 +1,35 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
using System;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> FromClientIP(string clientIP, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.ClientIP, clientIP, StringComparison.OrdinalIgnoreCase));
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but no calls were made.",
clientIP
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but didn't find it among the calls from IP(s) {1}.",
_ => clientIP, requests => requests.Select(request => request.ClientIP)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, string>(this, clientIP);
}
}

View File

@@ -0,0 +1,81 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
using System;
using WireMock.Constants;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingConnect(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.CONNECT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingDelete(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.DELETE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingGet(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.GET, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingHead(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.HEAD, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingOptions(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.OPTIONS, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPost(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.POST, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPatch(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PATCH, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingPut(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.PUT, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingTrace(string because = "", params object[] becauseArgs)
=> UsingMethod(HttpRequestMethod.TRACE, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingAnyMethod(string because = "", params object[] becauseArgs)
=> UsingMethod(Any, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> UsingMethod(string method, string because = "", params object[] becauseArgs)
{
var any = method == Any;
Func<IRequestMessage, bool> predicate = request => (any && !string.IsNullOrEmpty(request.Method)) ||
string.Equals(request.Method, method, StringComparison.OrdinalIgnoreCase);
var (filter, condition) = BuildFilterAndCondition(predicate);
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but no calls were made.",
method
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called using method {0}{reason}, but didn't find it among the methods {1}.",
_ => method,
requests => requests.Select(request => request.Method)
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
}

View File

@@ -0,0 +1,147 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using AnyOfTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Extensions;
using WireMock.Matchers;
using WireMock.Models;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
private const string MessageFormatNoCalls = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but no calls were made.";
private const string MessageFormat = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but didn't find it among the body/bodies {1}.";
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBody(string body, string because = "", params object[] becauseArgs)
{
return WithBody(new WildcardMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBody(IStringMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.Body, matcher);
return ExecuteAssertionWithBodyStringMatcher(matcher, because, becauseArgs, condition, filter, r => r.Body);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, string because = "", params object[] becauseArgs)
{
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, string because = "", params object[] becauseArgs)
{
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsJson(IObjectMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
return ExecuteAssertionWithBodyAsIObjectMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsJson);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsBytes(byte[] body, string because = "", params object[] becauseArgs)
{
return WithBodyAsBytes(new ExactObjectMatcher(body), because, becauseArgs);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithBodyAsBytes(ExactObjectMatcher matcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsBytes, matcher);
return ExecuteAssertionWithBodyAsIObjectMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsBytes);
}
private AndConstraint<WireMockAssertions> ExecuteAssertionWithBodyStringMatcher(
IStringMatcher matcher,
string because,
object[] becauseArgs,
Func<IReadOnlyList<IRequestMessage>, bool> condition,
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter,
Func<IRequestMessage, object?> expression
)
{
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
MessageFormatNoCalls,
FormatBody(matcher.GetPatterns())
)
.Then
.ForCondition(condition)
.FailWith(
MessageFormat,
_ => FormatBody(matcher.GetPatterns()),
requests => FormatBodies(requests.Select(expression))
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
private AndConstraint<WireMockAssertions> ExecuteAssertionWithBodyAsIObjectMatcher(
IObjectMatcher matcher,
string because,
object[] becauseArgs,
Func<IReadOnlyList<IRequestMessage>, bool> condition,
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter,
Func<IRequestMessage, object?> expression
)
{
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
MessageFormatNoCalls,
FormatBody(matcher.Value)
)
.Then
.ForCondition(condition)
.FailWith(
MessageFormat,
_ => FormatBody(matcher.Value),
requests => FormatBodies(requests.Select(expression))
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
private static string? FormatBody(object? body)
{
return body switch
{
null => null,
string str => str,
AnyOf<string, StringPattern>[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())),
byte[] bytes => $"byte[{bytes.Length}] {{...}}",
JToken jToken => jToken.ToString(Formatting.None),
_ => JToken.FromObject(body).ToString(Formatting.None)
};
}
private static string? FormatBodies(IEnumerable<object?> bodies)
{
var valueAsArray = bodies as object[] ?? bodies.ToArray();
return valueAsArray.Length == 1 ? FormatBody(valueAsArray[0]) : $"[ {string.Join(", ", valueAsArray.Select(FormatBody))} ]";
}
}

View File

@@ -0,0 +1,157 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> WitHeaderKey(string expectedKey, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request =>
{
return request.Headers?.Any(h => h.Key == expectedKey) == true;
});
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called with Header {0}{reason}.",
expectedKey
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called with Header {0}{reason}, but didn't find it among the calls with Header(s) {1}.",
_ => expectedKey,
requests => requests.Select(request => request.Headers)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, string>(this, expectedKey);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string value, string because = "", params object[] becauseArgs)
=> WithHeader(expectedKey, new[] { value }, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string[] expectedValues, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request =>
{
var headers = request.Headers?.ToArray() ?? [];
var matchingHeaderValues = headers.Where(h => h.Key == expectedKey).SelectMany(h => h.Value.ToArray()).ToArray();
if (expectedValues.Length == 1 && matchingHeaderValues.Length == 1)
{
return matchingHeaderValues[0] == expectedValues[0];
}
var trimmedHeaderValues = string.Join(",", matchingHeaderValues.Select(x => x)).Split(',').Select(x => x.Trim()).ToArray();
return expectedValues.Any(trimmedHeaderValues.Contains);
});
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called with Header {0} and Values {1}{reason}.",
expectedKey,
expectedValues
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called with Header {0} and Values {1}{reason}, but didn't find it among the calls with Header(s) {2}.",
_ => expectedKey,
_ => expectedValues,
requests => requests.Select(request => request.Headers)
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithoutHeaderKey(string unexpectedKey, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request =>
{
return request.Headers?.Any(h => h.Key == unexpectedKey) != true;
});
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} not to have been called with Header {0}{reason}.",
unexpectedKey
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} not to have been called with Header {0}{reason}, but found it among the calls with Header(s) {1}.",
_ => unexpectedKey,
requests => requests.Select(request => request.Headers)
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithoutHeader(string unexpectedKey, string value, string because = "", params object[] becauseArgs)
=> WithoutHeader(unexpectedKey, new[] { value }, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithoutHeader(string unexpectedKey, string[] expectedValues, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request =>
{
var headers = request.Headers?.ToArray() ?? [];
var matchingHeaderValues = headers.Where(h => h.Key == unexpectedKey).SelectMany(h => h.Value.ToArray()).ToArray();
if (expectedValues.Length == 1 && matchingHeaderValues.Length == 1)
{
return matchingHeaderValues[0] != expectedValues[0];
}
var trimmedHeaderValues = string.Join(",", matchingHeaderValues.Select(x => x)).Split(',').Select(x => x.Trim()).ToArray();
return !expectedValues.Any(trimmedHeaderValues.Contains);
});
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} not to have been called with Header {0} and Values {1}{reason}.",
unexpectedKey,
expectedValues
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} not to have been called with Header {0} and Values {1}{reason}, but found it among the calls with Header(s) {2}.",
_ => unexpectedKey,
_ => expectedValues,
requests => requests.Select(request => request.Headers)
);
FilterRequestMessages(filter);
return new AndConstraint<WireMockAssertions>(this);
}
}

View File

@@ -0,0 +1,36 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
using System;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> WithProxyUrl(string proxyUrl, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.ProxyUrl, proxyUrl, StringComparison.OrdinalIgnoreCase));
_chain
.BecauseOf(because, becauseArgs)
.Given(() => RequestMessages)
.ForCondition(requests => CallsCount == 0 || requests.Any())
.FailWith(
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but no calls were made.",
proxyUrl
)
.Then
.ForCondition(condition)
.FailWith(
"Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but didn't find it among the calls with {1}.",
_ => proxyUrl,
requests => requests.Select(request => request.ProxyUrl)
);
FilterRequestMessages(filter);
return new AndWhichConstraint<WireMockAssertions, string>(this, proxyUrl);
}
}

View File

@@ -0,0 +1,48 @@
// Copyright © WireMock.Net
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using WireMock.Matchers;
using WireMock.Server;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
public partial class WireMockAssertions
{
public const string Any = "*";
public int? CallsCount { get; }
public IReadOnlyList<IRequestMessage> RequestMessages { get; private set; }
private readonly AssertionChain _chain;
public WireMockAssertions(IWireMockServer subject, int? callsCount, AssertionChain chain)
{
CallsCount = callsCount;
RequestMessages = subject.LogEntries.Select(logEntry => logEntry.RequestMessage).ToList();
_chain = chain;
}
public (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, bool> predicate)
{
Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter = requests => requests.Where(predicate).ToList();
return (filter, requests => (CallsCount is null && filter(requests).Any()) || CallsCount == filter(requests).Count);
}
public (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, string?> expression, IStringMatcher matcher)
{
return BuildFilterAndCondition(r => matcher.IsMatch(expression(r)).IsPerfect());
}
public (Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> Filter, Func<IReadOnlyList<IRequestMessage>, bool> Condition) BuildFilterAndCondition(Func<IRequestMessage, object?> expression, IObjectMatcher matcher)
{
return BuildFilterAndCondition(r => matcher.IsMatch(expression(r)).IsPerfect());
}
public void FilterRequestMessages(Func<IReadOnlyList<IRequestMessage>, IReadOnlyList<IRequestMessage>> filter)
{
RequestMessages = filter(RequestMessages).ToList();
}
}

View File

@@ -0,0 +1,56 @@
// Copyright © WireMock.Net
using AwesomeAssertions.Primitives;
using WireMock.Server;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions;
/// <summary>
/// Contains a number of methods to assert that the <see cref="IWireMockServer"/> is in the expected state.
/// </summary>
public class WireMockReceivedAssertions : ReferenceTypeAssertions<IWireMockServer, WireMockReceivedAssertions>
{
private readonly AssertionChain _chain;
/// <summary>
/// Create a WireMockReceivedAssertions.
/// </summary>
/// <param name="server">The <see cref="IWireMockServer"/>.</param>
/// <param name="chain">The assertion chain</param>
public WireMockReceivedAssertions(IWireMockServer server, AssertionChain chain) : base(server, chain)
{
_chain = chain;
}
/// <summary>
/// Asserts if <see cref="IWireMockServer"/> has received no calls.
/// </summary>
/// <returns><see cref="WireMockAssertions"/></returns>
public WireMockAssertions HaveReceivedNoCalls()
{
return new WireMockAssertions(Subject, 0, _chain);
}
/// <summary>
/// Asserts if <see cref="IWireMockServer"/> has received a call.
/// </summary>
/// <returns><see cref="WireMockAssertions"/></returns>
public WireMockAssertions HaveReceivedACall()
{
return new WireMockAssertions(Subject, null, _chain);
}
/// <summary>
/// Asserts if <see cref="IWireMockServer"/> has received n-calls.
/// </summary>
/// <param name="callsCount"></param>
/// <returns><see cref="WireMockANumberOfCallsAssertions"/></returns>
public WireMockANumberOfCallsAssertions HaveReceived(int callsCount)
{
return new WireMockANumberOfCallsAssertions(Subject, callsCount, _chain);
}
/// <inheritdoc />
protected override string Identifier => "wiremockserver";
}

View File

@@ -0,0 +1,23 @@
// Copyright © WireMock.Net
using WireMock.Server;
// ReSharper disable once CheckNamespace
namespace WireMock.AwesomeAssertions
{
/// <summary>
/// Contains extension methods for custom assertions in unit tests.
/// </summary>
public static class WireMockExtensions
{
/// <summary>
/// Returns a <see cref="WireMockReceivedAssertions"/> object that can be used to assert the current <see cref="IWireMockServer"/>.
/// </summary>
/// <param name="instance">The WireMockServer</param>
/// <returns><see cref="WireMockReceivedAssertions"/></returns>
public static WireMockReceivedAssertions Should(this IWireMockServer instance)
{
return new WireMockReceivedAssertions(instance, AssertionChain.GetOrCreate());
}
}
}

View File

@@ -0,0 +1,5 @@
// Copyright © WireMock.Net
global using System.Linq;
global using AwesomeAssertions;
global using AwesomeAssertions.Execution;

View File

@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>AwesomeAssertions extensions for WireMock.Net</Description>
<AssemblyTitle>WireMock.Net.AwesomeAssertions</AssemblyTitle>
<Authors>Francesco Venturoli;Mahmoud Ali;Stef Heyenrath</Authors>
<TargetFrameworks>net47;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.AwesomeAssertions</AssemblyName>
<PackageId>WireMock.Net.AwesomeAssertions</PackageId>
<PackageTags>wiremock;AwesomeAssertions;UnitTest;Assert;Assertions</PackageTags>
<RootNamespace>WireMock.AwesomeAssertions</RootNamespace>
<ProjectGuid>{9565C395-FC5D-4CB1-8381-EC3D9DA74779}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AwesomeAssertions" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Minimal\WireMock.Net.Minimal.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
// Copyright © WireMock.Net
namespace WireMock.Net.Extensions.Routing.Delegates;
/// <summary>
/// Represents a handler for processing WireMock.Net HTTP requests and returning a response asynchronously.
/// </summary>
/// <param name="requestMessage">The incoming request message.</param>
/// <returns>A task that resolves to a <see cref="ResponseMessage"/>.</returns>
public delegate Task<IResponseMessage> WireMockHttpRequestHandler(IRequestMessage requestMessage);

View File

@@ -0,0 +1,10 @@
// Copyright © WireMock.Net
namespace WireMock.Net.Extensions.Routing.Delegates;
/// <summary>
/// Represents a middleware component for WireMock.Net HTTP request handling.
/// </summary>
/// <param name="next">The next request handler in the middleware pipeline.</param>
/// <returns>A <see cref="WireMockHttpRequestHandler"/> that processes the request.</returns>
public delegate WireMockHttpRequestHandler WireMockMiddleware(WireMockHttpRequestHandler next);

View File

@@ -0,0 +1,19 @@
// Copyright © WireMock.Net
using System.Collections.Immutable;
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class DictionaryExtensions
{
public static IDictionary<TKey, TValue> AddIf<TKey, TValue>(
this IDictionary<TKey, TValue> source,
bool condition,
TKey key,
TValue value,
IEqualityComparer<TKey>? keyComparer = null)
where TKey : notnull =>
condition
? source.ToImmutableDictionary(keyComparer).Add(key, value)
: source;
}

View File

@@ -0,0 +1,34 @@
// Copyright © WireMock.Net
using Microsoft.AspNetCore.Http;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class HttpResponseExtensions
{
public static async Task<ResponseMessage> ToResponseMessageAsync(
this HttpResponse response)
{
var headers = response.Headers.ToDictionary(
header => header.Key, header => new WireMockList<string?>(header.Value.ToArray()));
return new()
{
Headers = headers!,
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = await response.ReadBodyAsStringAsync(),
},
StatusCode = response.StatusCode,
};
}
public static async Task<string> ReadBodyAsStringAsync(this HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(response.Body);
return await reader.ReadToEndAsync();
}
}

View File

@@ -0,0 +1,16 @@
// Copyright © WireMock.Net
using JsonConverter.Abstractions;
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class RequestMessageExtensions
{
public static T? GetBodyAsJson<T>(
this IRequestMessage requestMessage,
IJsonConverter jsonConverter,
JsonConverterOptions? jsonOptions = null) =>
requestMessage.Body is not null
? jsonConverter.Deserialize<T>(requestMessage.Body, jsonOptions)
: default;
}

View File

@@ -0,0 +1,9 @@
// Copyright © WireMock.Net
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class StringExtensions
{
public static string ToMatchFullStringRegex(this string regex) =>
$"^{regex}$";
}

View File

@@ -0,0 +1,39 @@
// Copyright © WireMock.Net
using System.Reflection;
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class TaskExtensions
{
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Usage",
"VSTHRD003:Avoid awaiting foreign Tasks",
Justification = "Await is required here to transform base task to generic one.")]
public static async Task<object?> ToGenericTaskAsync(this Task task)
{
await task;
var taskType = task.GetType();
if (!IsAssignableToGenericTaskType(taskType))
{
return null;
}
return task
.GetType()
.GetProperty("Result", BindingFlags.Instance | BindingFlags.Public)!
.GetValue(task);
}
private static bool IsAssignableToGenericTaskType(Type type)
{
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Task<>) &&
type.GetGenericArguments()[0] != Type.GetType("System.Threading.Tasks.VoidTaskResult"))
{
return true;
}
return type.BaseType is not null && IsAssignableToGenericTaskType(type.BaseType);
}
}

View File

@@ -0,0 +1,17 @@
// Copyright © WireMock.Net
using WireMock.Net.Extensions.Routing.Delegates;
namespace WireMock.Net.Extensions.Routing.Extensions;
internal static class WireMockHttpRequestHandlerExtensions
{
public static WireMockHttpRequestHandler UseMiddleware(
this WireMockHttpRequestHandler handler, WireMockMiddleware middleware) =>
middleware(handler);
public static WireMockHttpRequestHandler UseMiddlewareCollection(
this WireMockHttpRequestHandler handler,
IReadOnlyCollection<WireMockMiddleware> middlewareCollection) =>
middlewareCollection.Aggregate(handler, UseMiddleware);
}

View File

@@ -0,0 +1,224 @@
// Copyright © WireMock.Net
using JsonConverter.Abstractions;
using WireMock.Net.Extensions.Routing.Models;
namespace WireMock.Net.Extensions.Routing.Extensions;
/// <summary>
/// Provides extension methods for mapping HTTP routes to handlers in <see cref="WireMockRouter"/>.
/// </summary>
public static class WireMockRouterExtensions
{
/// <summary>
/// Maps a GET request to a synchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapGet(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, object?> requestHandler) =>
source.Map(HttpMethod.Get.Method, pattern, requestHandler);
/// <summary>
/// Maps a GET request to an asynchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapGet(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
source.Map(HttpMethod.Get.Method, pattern, requestHandler);
/// <summary>
/// Maps a POST request to a synchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPost(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, object?> requestHandler) =>
source.Map(HttpMethod.Post.Method, pattern, requestHandler);
/// <summary>
/// Maps a POST request to an asynchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPost(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
source.Map(HttpMethod.Post.Method, pattern, requestHandler);
/// <summary>
/// Maps a POST request to a synchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPost<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Post.Method, pattern, requestHandler, jsonConverter, jsonOptions);
/// <summary>
/// Maps a POST request to an asynchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPost<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Post.Method, pattern, requestHandler, jsonConverter, jsonOptions);
/// <summary>
/// Maps a PUT request to a synchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPut(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, object?> requestHandler) =>
source.Map(HttpMethod.Put.Method, pattern, requestHandler);
/// <summary>
/// Maps a PUT request to an asynchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPut(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
source.Map(HttpMethod.Put.Method, pattern, requestHandler);
/// <summary>
/// Maps a PUT request to a synchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPut<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Put.Method, pattern, requestHandler, jsonConverter, jsonOptions);
/// <summary>
/// Maps a PUT request to an asynchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapPut<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Put.Method, pattern, requestHandler, jsonConverter, jsonOptions);
/// <summary>
/// Maps a DELETE request to a synchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapDelete(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, object?> requestHandler) =>
source.Map(HttpMethod.Delete.Method, pattern, requestHandler);
/// <summary>
/// Maps a DELETE request to an asynchronous request handler.
/// </summary>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapDelete(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
source.Map(HttpMethod.Delete.Method, pattern, requestHandler);
/// <summary>
/// Maps a DELETE request to a synchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapDelete<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Delete.Method, pattern, requestHandler, jsonConverter, jsonOptions);
/// <summary>
/// Maps a DELETE request to an asynchronous request handler with a typed body.
/// </summary>
/// <typeparam name="TRequest">The type of the request body.</typeparam>
/// <param name="source">The router to extend.</param>
/// <param name="pattern">The route pattern.</param>
/// <param name="requestHandler">The asynchronous request handler function.</param>
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
public static WireMockRouter MapDelete<TRequest>(
this WireMockRouter source,
string pattern,
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
IJsonConverter? jsonConverter = null,
JsonConverterOptions? jsonOptions = null) =>
source.Map(HttpMethod.Delete.Method, pattern, requestHandler, jsonConverter, jsonOptions);
}

View File

@@ -0,0 +1,35 @@
// Copyright © WireMock.Net
using WireMock.Matchers;
using WireMock.Net.Extensions.Routing.Delegates;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
namespace WireMock.Net.Extensions.Routing.Extensions;
/// <summary>
/// Provides extension methods for mapping HTTP requests to handlers in <see cref="WireMockServer"/>.
/// </summary>
public static class WireMockServerExtensions
{
/// <summary>
/// Maps a request to a WireMock.Net server using the specified method, path matcher, and request handler.
/// </summary>
/// <param name="source">The WireMock.Net server to extend.</param>
/// <param name="method">The HTTP method to match.</param>
/// <param name="pathMatcher">The matcher for the request path.</param>
/// <param name="httpRequestHandler">The handler to process the request.</param>
/// <returns>The current <see cref="WireMockServer"/> instance.</returns>
public static WireMockServer Map(
this WireMockServer source,
string method,
IStringMatcher pathMatcher,
WireMockHttpRequestHandler httpRequestHandler)
{
source
.Given(Request.Create().WithPath(pathMatcher).UsingMethod(method))
.RespondWith(Response.Create().WithCallback(req => httpRequestHandler(req)));
return source;
}
}

View File

@@ -0,0 +1,29 @@
// Copyright © WireMock.Net
namespace WireMock.Net.Extensions.Routing.Models;
/// <summary>
/// Represents request information for WireMock.Net routing, including the request message and route arguments.
/// </summary>
public class WireMockRequestInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="WireMockRequestInfo"/> class.
/// </summary>
/// <param name="request">The incoming request message.</param>
public WireMockRequestInfo(IRequestMessage request)
{
Request = request;
}
/// <summary>
/// Gets the incoming request message.
/// </summary>
public IRequestMessage Request { get; }
/// <summary>
/// Gets or initializes the route arguments extracted from the request path.
/// </summary>
public IDictionary<string, object> RouteArgs { get; init; } =
new Dictionary<string, object>();
}

View File

@@ -0,0 +1,24 @@
// Copyright © WireMock.Net
namespace WireMock.Net.Extensions.Routing.Models;
/// <summary>
/// Represents request information with a strongly-typed deserialized body for WireMock.Net routing.
/// </summary>
/// <typeparam name="TBody">The type of the deserialized request body.</typeparam>
public sealed class WireMockRequestInfo<TBody> : WireMockRequestInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="WireMockRequestInfo{TBody}"/> class.
/// </summary>
/// <param name="request">The incoming request message.</param>
public WireMockRequestInfo(IRequestMessage request)
: base(request)
{
}
/// <summary>
/// Gets or initializes the deserialized request body.
/// </summary>
public TBody? Body { get; init; }
}

View File

@@ -0,0 +1,138 @@
# WireMock.Net.Extensions.Routing
**WireMock.Net.Extensions.Routing** extends [WireMock.Net](https://github.com/wiremock/wiremock) with modern, minimal-API-style routing for .NET. It provides extension methods for expressive, maintainable, and testable HTTP routing, inspired by [ASP.NET Core Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-9.0).
---
## Motivation
While [WireMock.Net](https://github.com/WireMock-Net/WireMock.Net) is a powerful tool for HTTP mocking in .NET, its native API for defining routes and request handlers can be verbose and require significant boilerplate. Setting up even simple endpoints often involves multiple chained method calls, manual parsing of request data, and repetitive configuration, which can make tests harder to read and maintain.
**WireMock.Net.Extensions.Routing** addresses these pain points by introducing a concise, fluent, and minimal-API-inspired approach to routing. This makes your test code:
- **More readable:** Route definitions are clear and expressive, closely resembling production minimal APIs.
- **Easier to maintain:** Less boilerplate means fewer places for errors and easier refactoring.
- **Faster to write:** Define routes and handlers in a single line, with strong typing and async support.
### Example: Native WireMock.Net vs. WireMock.Net.Extensions.Routing
#### Native WireMock.Net
```csharp
server.Given(
Request.Create().WithPath("/hello").UsingGet()
)
.RespondWith(
Response.Create().WithBody("Hello, world!")
);
server.Given(
Request.Create().WithPath("/user/*").UsingGet()
)
.RespondWith(
Response.Create().WithCallback(request =>
{
var id = request.PathSegments[1];
// ...fetch user by id...
return new ResponseMessage { Body = $"User: {id}" };
})
);
```
#### With WireMock.Net.Extensions.Routing
```csharp
router.MapGet("/hello", _ => "Hello, world!");
router.MapGet("/user/{id:int}", requestInfo =>
{
var id = requestInfo.RouteArgs["id"];
// ...fetch user by id...
return $"User: {id}";
});
```
With **WireMock.Net.Extensions.Routing**, you get:
- Minimal, one-line route definitions
- Typed route parameters (e.g., `{id:int}`)
- Direct access to parsed route arguments and request bodies
- Async handler support
This leads to more maintainable, scalable, and production-like test code.
---
## Features
- Minimal API-style route definitions for WireMock.Net
- Strongly-typed request handling
- Routing parameters with constraints (`int` and `string` are currently supported)
- Asynchronous handlers
- Fluent, composable routing extensions
- Easy integration with existing WireMock.Net servers
- .NET 8+ support
---
## Installation
Install from NuGet:
```shell
dotnet add package WireMock.Net.Extensions.Routing
```
---
## Quick Start
```csharp
using System.Net.Http.Json;
using WireMock.Net.Extensions.Routing;
using WireMock.Net.Extensions.Routing.Extensions;
using WireMock.Server;
var server = WireMockServer.Start();
var router = new WireMockRouter(server);
router.MapGet("/hello", _ => "Hello, world!");
using var client = server.CreateClient();
var result = await client.GetFromJsonAsync<string>("/hello");
// Hello, world!
```
---
## Usage
### Routing with route parameters
```csharp
router.MapGet("/user/{id:int}", async requestInfo => {
var userId = requestInfo.RouteArgs["id"];
// var user = await ...
return user;
});
```
### Strongly-Typed Request Info
```csharp
router.MapPost<Item>("/api/items", requestInfo => {
var item = requestInfo.Body!;
// process item
return Results.Json(new { success = true });
});
```
### Supported Methods
- `MapGet`, `MapPost`, `MapPut`, `MapDelete`
---
## Documentation
- [API Reference](./src/WireMock.Net.Extensions.Routing/)
- [WireMock.Net Documentation](https://github.com/WireMock-Net/WireMock.Net)

View File

@@ -0,0 +1,107 @@
// Copyright © WireMock.Net
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.RegularExpressions;
using WireMock.Net.Extensions.Routing.Extensions;
namespace WireMock.Net.Extensions.Routing.Utils;
internal static class RoutePattern
{
private static readonly Regex ArgRegex =
new(@"{(?'name'\w+)(?::(?'type'\w+))?}", RegexOptions.Compiled);
public static IDictionary<string, object> GetArgs(string pattern, string route) =>
TryGetArgs(pattern, route, out var args)
? args
: throw new InvalidOperationException(
$"Url {route} does not match route pattern {pattern}");
public static bool TryGetArgs(
string pattern, string route, [NotNullWhen(true)] out IDictionary<string, object>? args)
{
var regex = new Regex(ToRegex(pattern), RegexOptions.IgnoreCase);
var match = regex.Match(route);
if (!match.Success)
{
args = null;
return false;
}
var routeArgTypeMap = GetArgTypeMap(pattern);
args = match.Groups
.Cast<Group>()
.Where(g => g.Index > 0)
.ToDictionary(g => g.Name, g => routeArgTypeMap[g.Name].Parse(g.Value));
return true;
}
public static string ToRegex(string pattern)
{
return ArgRegex
.Replace(pattern, m => $"(?'{m.Groups["name"].Value}'{GetArgMatchingRegex(m)})")
.ToMatchFullStringRegex();
static string GetArgMatchingRegex(Match match) =>
ArgType.GetByName(match.Groups["type"].Value).GetRegex();
}
private static IDictionary<string, ArgType> GetArgTypeMap(string pattern) =>
ArgRegex
.Matches(pattern)
.ToDictionary(
m => m.Groups["name"].Value, m => ArgType.GetByName(m.Groups["type"].Value));
private abstract record ArgType
{
private ArgType(string name)
{
Name = name;
}
public string Name { get; }
public static ArgType String { get; } = new StringArgType();
public static ArgType Int { get; } = new IntArgType();
private static IReadOnlyCollection<ArgType> All { get; } =
typeof(ArgType)
.GetProperties(BindingFlags.Public | BindingFlags.Static)
.Where(p => p.PropertyType.IsAssignableTo(typeof(ArgType)))
.Select(p => p.GetValue(null))
.Cast<ArgType>()
.ToList();
private static IReadOnlyDictionary<string, ArgType> MapByName { get; } =
All.ToDictionary(x => x.Name);
public static ArgType GetByName(string name) =>
GetByNameOrDefault(name)
?? throw new InvalidOperationException($"Route argument type {name} is not found");
public static ArgType? GetByNameOrDefault(string name) =>
!string.IsNullOrEmpty(name)
? MapByName.GetValueOrDefault(name)
: String;
public abstract object Parse(string input);
public abstract string GetRegex();
private sealed record StringArgType() : ArgType("string")
{
public override object Parse(string input) => input;
public override string GetRegex() => @".*";
}
private sealed record IntArgType() : ArgType("int")
{
public override object Parse(string input) => int.Parse(input);
public override string GetRegex() => @"-?\d+";
}
}
}

View File

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>WireMock.Net.Routing extends WireMock.Net with modern, minimal-API-style routing for .NET</Description>
<Authors>Gennadii Saltyshchak</Authors>
<TargetFrameworks>net8.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>tdd;mock;http;wiremock;test;server;unittest;routing;minimalapi</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageReadmeFile>README.md</PackageReadmeFile>
<ImplicitUsings>enable</ImplicitUsings>
<!--<TreatWarningsAsErrors>true</TreatWarningsAsErrors>-->
</PropertyGroup>
<ItemGroup>
<None Include="..\..\README.md" Link="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Minimal\WireMock.Net.Minimal.csproj" />
</ItemGroup>
</Project>

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