Compare commits

...

66 Commits

Author SHA1 Message Date
Stef Heyenrath
a2df91a2a2 1.0.3.4 2018-03-04 10:50:30 +01:00
Stef Heyenrath
1442e874cf Remove codecov.io 2018-03-04 10:34:07 +01:00
Alastair Crabtree
3f2c139f90 feat: add WithBody(req => dostuff) style callback (#102) 2018-03-03 08:38:03 +00:00
Stef Heyenrath
2b8a58c68c #100 2018-03-02 14:35:10 +01:00
Stef Heyenrath
977d91109e ICallbackResponseBuilder + added more unit-tests (#101)
* Callback

* Add more tests
2018-03-02 09:12:36 +00:00
Stef Heyenrath
22298114d7 Fix ResponseMessageTransformer 2018-02-28 18:05:10 +01:00
Stef Heyenrath
0be8ee1174 Fix ResponseMessageTransformer (BodyAsJson) 2018-02-28 09:24:27 +01:00
Stef Heyenrath
17741cbc50 FIx for IsStarted (#93) 2018-02-28 08:34:57 +01:00
Stef Heyenrath
938d3fb095 Replace log4net by custom logger (#94) (#96)
* Replace log4net by custom logger

* WireMockNullLogger
2018-02-28 07:01:03 +00:00
Stef Heyenrath
e850126184 Unittest fix (#95)
* fix tests

* fix tests
2018-02-27 11:17:36 +00:00
Stef Heyenrath
ad6c59e3b5 1.0.3.3 2018-02-24 09:04:21 +01:00
Stef Heyenrath
0c25b2e9f2 Json fixes (#91) (#92)
* Fixes for JsonPath

* More tests

* Fixes + added tests
2018-02-23 12:29:43 +00:00
Stef Heyenrath
1ffd56701c fix unit-test 2018-02-14 20:38:19 +01:00
Stef Heyenrath
4f87146622 1.0.3.2 2018-02-14 19:35:51 +01:00
Stef Heyenrath
693778659e Concurrent issue (#88) (#90)
* concurrent

* uni tests
2018-02-14 18:30:06 +00:00
Stef Heyenrath
51070dab63 1.0.3.1 releasenotes 2018-02-14 17:17:05 +01:00
Stef Heyenrath
e21582aacf Add log4net logging (#89)
* logging + fixed proxy isses

* Add more logging

* comments

* 1.0.3.1
2018-02-14 16:13:05 +00:00
Stef Heyenrath
9778c5adbe Use EnhancedFileSystemWatcher.cs instead of NuGet 2018-02-05 08:36:50 +01:00
Stef Heyenrath
1caa769618 1.0.3 + release notes 2018-02-04 10:47:33 +01:00
Stef Heyenrath
cf4e83b10b Fix typo 2018-02-04 10:31:11 +01:00
Stef Heyenrath
95a201573a #86 2018-02-04 10:22:56 +01:00
Stef Heyenrath
b248c8c6e5 EnhancedFileSystemWatcher (#86) 2018-02-03 23:22:29 +01:00
Stef Heyenrath
180526c8b4 self-signed-certificate + #83 2018-02-03 12:06:12 +01:00
Stef Heyenrath
361d40189b Fixed https proxy for netstandard 1.3 and netstandard 2.0 (#85) 2018-02-02 22:52:08 +01:00
Stef Heyenrath
061eb93fd0 Refactor HttpClientHandler code 2018-02-02 18:11:37 +01:00
Stef Heyenrath
e5b2ad0543 SetBody (#81) 2018-02-02 15:42:25 +01:00
Stef Heyenrath
66b2ff16de Implemented #82 2018-02-02 11:17:37 +01:00
Stef Heyenrath
40ff8514ac BodyAsJson (#80) 2018-01-31 12:41:10 +01:00
Stef Heyenrath
cdcaaa970a 1.0.2.13 2018-01-23 08:09:19 +01:00
Stef Heyenrath
d07a89c907 Merge remote-tracking branch 'origin/master' 2018-01-23 08:07:00 +01:00
Stef Heyenrath
141ed5d96c code update 2018-01-23 08:06:55 +01:00
vladimir-fed
6d60b3773a Fix missed content headers (#79) 2018-01-23 08:05:12 +01:00
Stef Heyenrath
e6af765777 1.0.2.12 2018-01-16 20:46:43 +01:00
Stef Heyenrath
97d80ada11 Fixed issue #76 (#77)
#76
2018-01-16 20:44:59 +01:00
Stef Heyenrath
51bd9ec186 Add WireMock.Net.WebApplication example (#75) 2018-01-11 19:38:58 +01:00
Stef Heyenrath
da798a59aa Fix wiki link to Stubbing & Request Matching 2018-01-10 16:33:32 +01:00
Stef Heyenrath
71196b51c9 Fixed issue with same Mapping Guid (#73) 2017-12-20 20:51:51 +01:00
Stef Heyenrath
d0fc889f42 Fix for url encoded path + params (1.0.2.10) - #72
Fix for url encoded path + params (1.0.2.10)
2017-12-12 18:18:04 +01:00
Stef Heyenrath
fd5bc203c3 1.0.2.9 2017-12-07 22:17:35 +01:00
Stef Heyenrath
601af2d6b2 Fixed restricted headers on response (#71)
* Fixed restricted headers on response

* appveyor
2017-12-07 22:16:19 +01:00
Stef Heyenrath
ea16ee866b 1.0.2.8 2017-11-23 20:54:30 +01:00
Stef Heyenrath
ee0cb6e670 Added unit-test for #68
Added unit-test for #68
2017-11-22 21:33:40 +01:00
Alastair Crabtree
798603118c bug: fix supporting the Patch method and logging the body (#67)
* bug: fix supporting the Patch method and logging the body

- Patch not configured to support Body
- Add a unit test

* chore: typo fixed

* Added / reordered tests for PATCH method
2017-11-20 19:32:36 +01:00
Alastair Crabtree
208303729e bug: Fix admin api client definition returning the wrong types (#65)
* bug: Fix admin api client definition returning the wrong types

- IFluentMockServerAdmin get, find and get all requests should return a log entry model
- Add tests for get and find using the rest ease api client

* Fix Build status and rename tests
2017-11-19 20:44:05 +01:00
Stef Heyenrath
d39e9ef7fa Fixed readme 2017-11-19 11:47:42 +01:00
Stef Heyenrath
431e5656ca <DebugType>full</DebugType> 2017-11-19 11:37:50 +01:00
Stef Heyenrath
fa919343ac <DebugType>portable</DebugType> 2017-11-19 11:32:39 +01:00
Stef Heyenrath
d0b48e2967 DebugType, IncludeSource and IncludeSymbols set to 'true' 2017-11-19 10:39:11 +01:00
Stef Heyenrath
018d2a904d 1.0.2.7 2017-11-18 13:49:22 +01:00
Stef Heyenrath
939a5a61ab 1.0.2.7 2017-11-18 13:48:12 +01:00
vladimir-fed
a15e6747b0 Fix issue with concurrent logging (#63)
* Fix issue with concurrent logging

* Fix namespace + code format/cleanup
2017-11-18 12:22:19 +01:00
Alastair Crabtree
6c38400827 Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating (#62)
* feat: Add the Host, Protocol Port and Origin to the Request message

- Add new fields during request message creation, derived from the Uri object
- Allow the new fields to be accessed in the templating engine
- Add tests for the new fields

* source code file reformat

* appveyor
2017-11-18 12:03:13 +01:00
Stef Heyenrath
cb1117fdaa IHeadersAndCookiesRequestBuilder 2017-11-11 10:09:41 +01:00
Stef Heyenrath
e25c873765 Update ProxyAndRecord
ProxyAndRecord does not save query-parameters, headers and body (#57)
2017-11-07 21:52:30 +01:00
Stef Heyenrath
d83f308591 1.0.2.6 2017-10-30 08:49:16 +01:00
Oleksandr Liakhevych
c8c9ab99c5 Fix proxy headers handling (#60)
* Fix proxy headers handling

* Small refactor and moved proxy tests to new test-file.
2017-10-28 18:59:34 +02:00
Oleksandr Liakhevych
d134684bcb Add ability to provide multiple values for headers in response (#59)
* Add ability to provide multiple values for headers

* Updated json model
2017-10-27 21:49:03 +02:00
Stef Heyenrath
a96b7bca1e WithBodyFromFile (relative) 2017-10-27 12:12:13 +02:00
Stef Heyenrath
cbe6a0a2b4 WithBodyFromFile (#56) 2017-10-25 21:33:57 +02:00
Stef Heyenrath
15370a89ca 1.0.2.5 2017-10-24 18:12:39 +02:00
Stef Heyenrath
656f7f5432 HttpClientHelper : BodyAsBytes 2017-10-23 20:56:01 +02:00
deeptowncitizen
bcdc3d646a fix header (#55) 2017-10-23 20:25:06 +02:00
Stef Heyenrath
10350fac04 Merge branch 'appbuilder' 2017-10-18 20:19:03 +02:00
Stef Heyenrath
37244d5c2f PreWireMockMiddlewareInit / PostWireMockMiddlewareInit 2017-10-17 20:47:19 +02:00
Stef Heyenrath
07f03997c0 Fix issues with Bytes for Response 2017-10-14 10:48:58 +02:00
Stef Heyenrath
7c289d44a7 Update client interface for Scenarios 2017-10-10 18:21:22 +02:00
146 changed files with 5909 additions and 2308 deletions

168
CHANGELOG.md Normal file
View File

@@ -0,0 +1,168 @@
# 1.0.3.2 (14 February 2018)
- [#90](https://github.com/WireMock-Net/WireMock.Net/pull/90) - Concurrent issue (#88) contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#89](https://github.com/WireMock-Net/WireMock.Net/pull/89) - Add log4net logging contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#88](https://github.com/WireMock-Net/WireMock.Net/issues/88) - Bug: Standalone server throws 500 error when receiving concurrent requests +fix
- [#87](https://github.com/WireMock-Net/WireMock.Net/issues/87) - Feature: Add logging
Commits: 51070dab63...693778659e
# 1.0.3.1 (14 February 2018)
- [#89](https://github.com/WireMock-Net/WireMock.Net/pull/89) - Add log4net logging contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#87](https://github.com/WireMock-Net/WireMock.Net/issues/87) - Feature: Add logging
Commits: ...
# 1.0.3 (04 February 2018)
- [#86](https://github.com/WireMock-Net/WireMock.Net/issues/86) - Feature : Add FileSystemWatcher logic for watching static mapping files +feature
- [#85](https://github.com/WireMock-Net/WireMock.Net/issues/85) - Bug: https for netstandard does not work ? +fix
- [#83](https://github.com/WireMock-Net/WireMock.Net/issues/83) - Feature : Add also a method in IProxyResponseBuilder to provide proxy-settings +feature
- [#82](https://github.com/WireMock-Net/WireMock.Net/issues/82) - Feature: make it possible to ignore some headers when proxying +feature
- [#81](https://github.com/WireMock-Net/WireMock.Net/issues/81) - Feature: When using proxy, only BodyAsBytes in case of binary data?
- [#80](https://github.com/WireMock-Net/WireMock.Net/issues/80) - Feature: When using proxy, in case Content-Type is JSON, use BodyAsJson in Response
Commits: 40ff8514ac...cf4e83b10b
# 1.0.2.13 (23 January 2018)
- [#79](https://github.com/WireMock-Net/WireMock.Net/pull/79) - Fix missed content headers contributed by ([vladimir-fed](https://github.com/vladimir-fed))
- [#78](https://github.com/WireMock-Net/WireMock.Net/issues/78) - WireMock not working when attempting to access from anything other than localhost.
- [#57](https://github.com/WireMock-Net/WireMock.Net/issues/57) - ProxyAndRecord does not save query-parameters, headers and body +fix
Commits: 6d60b3773a...cdcaaa970a
# 1.0.2.12 (16 January 2018)
- [#77](https://github.com/WireMock-Net/WireMock.Net/pull/77) - Fixed issue #76 contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#76](https://github.com/WireMock-Net/WireMock.Net/issues/76) - Bug: IFluentMockServerAdmin is missing content-type for some POST/PUT calls
- [#75](https://github.com/WireMock-Net/WireMock.Net/pull/75) - Add WireMock.Net.WebApplication example contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#74](https://github.com/WireMock-Net/WireMock.Net/pull/74) - Capturing the index of the existing mapping before removing and insert the updated mapping at the same index of the list contributed by ([raghavendrabankapur](https://github.com/raghavendrabankapur))
- [#73](https://github.com/WireMock-Net/WireMock.Net/issues/73) - Updated mapping is not being picked and responded with the response
Commits: da798a59aa...e6af765777
# 1.0.2.11 (20 December 2017)
- [#72](https://github.com/WireMock-Net/WireMock.Net/issues/72) - Matching WithParam on OData End Points
Commits: 71196b51c9...71196b51c9
# 1.0.2.9 (07 December 2017)
- [#71](https://github.com/WireMock-Net/WireMock.Net/pull/71) - Fixed restricted headers on response contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#69](https://github.com/WireMock-Net/WireMock.Net/issues/69) - Instructions are incorrect (?)
Commits: 601af2d6b2...fd5bc203c3
# 1.0.2.10 (12 December 2017)
- [#70](https://github.com/WireMock-Net/WireMock.Net/issues/70) - Proxy/Intercept pattern is throwing a keep alive header error with net461
Commits: d0fc889f42...d0fc889f42
# 1.0.2.8 (23 November 2017)
- [#68](https://github.com/WireMock-Net/WireMock.Net/issues/68) - Full path required in Stub
- [#67](https://github.com/WireMock-Net/WireMock.Net/pull/67) - bug: fix supporting the Patch method and logging the body contributed by Alastair Crabtree ([alastairtree](https://github.com/alastairtree))
- [#65](https://github.com/WireMock-Net/WireMock.Net/pull/65) - bug: Fix admin api client definition returning the wrong types contributed by Alastair Crabtree ([alastairtree](https://github.com/alastairtree))
- [#64](https://github.com/WireMock-Net/WireMock.Net/issues/64) - Pull Requests do not trigger test + codecoverage ?
Commits: d0b48e2967...ea16ee866b
# 1.0.2.7 (18 November 2017)
- [#63](https://github.com/WireMock-Net/WireMock.Net/pull/63) - Fix issue with concurrent logging contributed by ([vladimir-fed](https://github.com/vladimir-fed))
- [#62](https://github.com/WireMock-Net/WireMock.Net/pull/62) - Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating contributed by Alastair Crabtree ([alastairtree](https://github.com/alastairtree))
- [#61](https://github.com/WireMock-Net/WireMock.Net/issues/61) - Partial mapping
- [#53](https://github.com/WireMock-Net/WireMock.Net/issues/53) - New feature request: Access to Owin pipeline
- [#42](https://github.com/WireMock-Net/WireMock.Net/issues/42) - Enhancement - Save/load request logs to/from disk +feature
- [#27](https://github.com/WireMock-Net/WireMock.Net/issues/27) - New feature: Record and Save
Commits: e25c873765...018d2a904d
# 1.0.2.6 (30 October 2017)
- [#60](https://github.com/WireMock-Net/WireMock.Net/pull/60) - Fix proxy headers handling contributed by Oleksandr Liakhevych ([Dreamescaper](https://github.com/Dreamescaper))
- [#59](https://github.com/WireMock-Net/WireMock.Net/pull/59) - Add ability to provide multiple values for headers in response contributed by Oleksandr Liakhevych ([Dreamescaper](https://github.com/Dreamescaper))
- [#58](https://github.com/WireMock-Net/WireMock.Net/issues/58) - Multiple headers with same name +feature
- [#56](https://github.com/WireMock-Net/WireMock.Net/issues/56) - WithBodyFromFile Support +feature
- [#54](https://github.com/WireMock-Net/WireMock.Net/issues/54) - Proxy for AWS: Error unmarshalling response back from AWS +fix
Commits: cbe6a0a2b4...d83f308591
# 1.0.2.5 (24 October 2017)
- [#55](https://github.com/WireMock-Net/WireMock.Net/pull/55) - Fix the problem with headers passthrough contributed by deeptowncitizen ([deeptowncitizen](https://github.com/deeptowncitizen)) +fix
- [#52](https://github.com/WireMock-Net/WireMock.Net/issues/52) - SimMetrics.NET error when trying to install NuGet Package
- [#48](https://github.com/WireMock-Net/WireMock.Net/issues/48) - Stateful support +feature
- [#44](https://github.com/WireMock-Net/WireMock.Net/issues/44) - Bug: Server not listening after Start() returns (on macOS) +fix
Commits: 7c289d44a7...15370a89ca
# 1.0.2.4 (10 October 2017)
- [#51](https://github.com/WireMock-Net/WireMock.Net/pull/51) - Observable logs contributed by deeptowncitizen ([deeptowncitizen](https://github.com/deeptowncitizen))
- [#50](https://github.com/WireMock-Net/WireMock.Net/issues/50) - New Feature: Callbacks
- [#49](https://github.com/WireMock-Net/WireMock.Net/pull/49) - stateful behavior contributed by deeptowncitizen ([deeptowncitizen](https://github.com/deeptowncitizen))
- [#47](https://github.com/WireMock-Net/WireMock.Net/issues/47) - Feature: add matcher details to Request to see which matchers match/not match +feature
- [#46](https://github.com/WireMock-Net/WireMock.Net/issues/46) - Log the ip-address from the client/caller also in the RequestLog +feature
- [#45](https://github.com/WireMock-Net/WireMock.Net/pull/45) - Add RequestLogExpirationDuration and MaxRequestLogCount (#43) contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#43](https://github.com/WireMock-Net/WireMock.Net/issues/43) - Feature: Add RequestLogExpirationDuration and MaxRequestLogCount
- [#41](https://github.com/WireMock-Net/WireMock.Net/pull/41) - Dotnet 20 preview final contributed by Stef Heyenrath ([StefH](https://github.com/StefH)) +feature
- [#40](https://github.com/WireMock-Net/WireMock.Net/pull/40) - Expose more settings to stand-alone app contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#39](https://github.com/WireMock-Net/WireMock.Net/pull/39) - Listen on http://*:9090 contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#38](https://github.com/WireMock-Net/WireMock.Net/issues/38) - Bug: support also listening on *:{port}
- [#37](https://github.com/WireMock-Net/WireMock.Net/issues/37) - Wrong Request Match result is returning
- [#36](https://github.com/WireMock-Net/WireMock.Net/issues/36) - How to implement a request body-dependent response?
- [#35](https://github.com/WireMock-Net/WireMock.Net/pull/35) - Revert changes that were made by mistake in prior PR contributed by ([phillee007](https://github.com/phillee007))
- [#34](https://github.com/WireMock-Net/WireMock.Net/issues/34) - Where is SearchLogsFor method?
- [#33](https://github.com/WireMock-Net/WireMock.Net/issues/33) - Issue with launching sample code (StandAlone server) +fix
- [#32](https://github.com/WireMock-Net/WireMock.Net/pull/32) - [Feature] Add support for client certificate password and test with real services that require client certificate auth contributed by ([phillee007](https://github.com/phillee007)) +feature
- [#31](https://github.com/WireMock-Net/WireMock.Net/issues/31) - Feature request: Nuget package for standalone version +feature
- [#20](https://github.com/WireMock-Net/WireMock.Net/issues/20) - Add client certificate authentication
- [#19](https://github.com/WireMock-Net/WireMock.Net/issues/19) - Is this the same as Mock4Net?
- [#15](https://github.com/WireMock-Net/WireMock.Net/issues/15) - New feature: Proxying +feature
Commits: 538195551d...e87e09e10d
# 1.02.1 (14 June 2017)
- [#30](https://github.com/WireMock-Net/WireMock.Net/issues/30) - [Feature] Disable partial mappings by default in standalone version +fix
- [#29](https://github.com/WireMock-Net/WireMock.Net/issues/29) - Support of .Net 4.0
- [#28](https://github.com/WireMock-Net/WireMock.Net/issues/28) - Facing issue with WildcardMatcher and '?'
Commits: 84db9bbf0d...7111ab384b
# 1.0.2.0 (05 May 2017)
- [#26](https://github.com/WireMock-Net/WireMock.Net/pull/26) - merge netstandard into main contributed by Stef Heyenrath ([StefH](https://github.com/StefH))
- [#25](https://github.com/WireMock-Net/WireMock.Net/issues/25) - Upgrade to vs2017 +feature
- [#23](https://github.com/WireMock-Net/WireMock.Net/issues/23) - Consider port to .Net Core
- [#21](https://github.com/WireMock-Net/WireMock.Net/issues/21) - Admin static json mappings +feature
Commits: b547993415...8d9cef6dd1
# 1.0.1.2 (27 February 2017)
- [#24](https://github.com/WireMock-Net/WireMock.Net/pull/24) - Body Encoding contributed by Sebastian Bebrys ([sbebrys](https://github.com/sbebrys))
- [#22](https://github.com/WireMock-Net/WireMock.Net/issues/22) - Add basic-authentication for accessing admin-interface +feature
- [#8](https://github.com/WireMock-Net/WireMock.Net/issues/8) - admin rest api
Commits: bb35f55bbb...02803562c6

BIN
GitReleaseNotes.exe Normal file

Binary file not shown.

5
GitReleaseNotes.txt Normal file
View File

@@ -0,0 +1,5 @@
https://github.com/GitTools/GitReleaseNotes
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3.4
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /allTags

View File

@@ -2,10 +2,9 @@
A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based http://WireMock.org A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) which mimics the functionality from the JAVA based http://WireMock.org
[![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net) [![Build status](https://ci.appveyor.com/api/projects/status/b3n6q3ygbww4lyls?svg=true)](https://ci.appveyor.com/project/StefH/wiremock-net)
[![codecov](https://codecov.io/gh/WireMock-Net/WireMock.Net/branch/master/graph/badge.svg)](https://codecov.io/gh/WireMock-Net/WireMock.Net) [![Coverage Status](https://coveralls.io/repos/github/WireMock-Net/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/WireMock-Net/WireMock.Net?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/StefH/WireMock.Net/badge.svg?branch=master)](https://coveralls.io/github/StefH/WireMock.Net?branch=master) [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues)
[![GitHub issues](https://img.shields.io/github/issues/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/issues) [![GitHub stars](https://img.shields.io/github/stars/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/stargazers)
[![GitHub stars](https://img.shields.io/github/stars/StefH/WireMock.Net.svg)](https://github.com/StefH/WireMock.Net/stargazers)
| Name | NuGet | | Name | NuGet |
| ---- | ----- | | ---- | ----- |
@@ -28,7 +27,7 @@ To build you need:
## Stubbing ## Stubbing
A core feature of WireMock.Net is the ability to return canned/predefined HTTP responses for requests matching criteria, see [Wiki : Stubbing](https://github.com/StefH/WireMock.Net/wiki/Stubbing). A core feature of WireMock.Net is the ability to return canned/predefined HTTP responses for requests matching criteria, see [Wiki : Stubbing & Request Matching](https://github.com/WireMock-Net/WireMock.Net/wiki/Stubbing-and-Request-Matching).
## Using WireMock in UnitTest framework ## Using WireMock in UnitTest framework
You can use your favorite test framework and use WireMock within your tests, see You can use your favorite test framework and use WireMock within your tests, see
@@ -43,6 +42,16 @@ This is quite straight forward to launch a mock server within a console applicat
### SSL ### SSL
You can start a standalone mock server listening for HTTPS requests. To do so, there is just a flag to set when creating the server: You can start a standalone mock server listening for HTTPS requests. To do so, there is just a flag to set when creating the server:
```csharp ```csharp
var server = FluentMockServer.Start(port: 8443, ssl: true); var server1 = FluentMockServer.Start(port: 8443, ssl: true);
// or like this
var server2 = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091", "https://localhost:9443" }
});
``` ```
Obviously you need a certificate registered on your box, properly associated with your application and the port number that will be used. This is not really specific to WireMock, not very straightforward and hence the following stackoverflow thread might come handy: [Httplistener with https support](http://stackoverflow.com/questions/11403333/httplistener-with-https-support)
- In case when using **net 4.5.2** or **net 4.6**, you need a certificate registered on your box, properly associated with your application and the port number that will be used. This is not really specific to WireMock.Net, not very straightforward and hence the following stackoverflow thread might come handy: [Httplistener with https support](http://stackoverflow.com/questions/11403333/httplistener-with-https-support).
- When using **netstandard**, WireMock.Net uses a self signed certificate (which can be overriden if you like) to host https urls.

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.13 VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF242EDF-7133-4277-9A0C-18744DE08707}"
EndProject EndProject
@@ -9,7 +9,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.runsettings = .runsettings .runsettings = .runsettings
appveyor.yml = appveyor.yml appveyor.yml = appveyor.yml
CHANGELOG.md = CHANGELOG.md
codecov-local.cmd = codecov-local.cmd codecov-local.cmd = codecov-local.cmd
GitReleaseNotes.txt = GitReleaseNotes.txt
README.md = README.md README.md = README.md
EndProjectSection EndProjectSection
EndProject EndProject
@@ -21,11 +23,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net", "src\WireMoc
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Tests", "test\WireMock.Net.Tests\WireMock.Net.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Tests", "test\WireMock.Net.Tests\WireMock.Net.Tests.csproj", "{31DC2EF8-C3FE-467D-84BE-FB5D956E612E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NETCoreApp", "examples\WireMock.Net.Console.NETCoreApp\WireMock.Net.Console.NETCoreApp.csproj", "{FE281639-B014-4C8A-96FA-141164A74713}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Record.NETCoreApp", "examples\WireMock.Net.Console.Record.NETCoreApp\WireMock.Net.Console.Record.NETCoreApp.csproj", "{1995E414-F197-4AB4-90C2-68D806B5AF59}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Proxy.NETCoreApp", "examples\WireMock.Net.Console.Record.NETCoreApp\WireMock.Net.Console.Proxy.NETCoreApp.csproj", "{1995E414-F197-4AB4-90C2-68D806B5AF59}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{058D4B6C-C03E-49D0-91DB-A535B058FA0D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.StandAlone", "src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj", "{B6269AAC-170A-43D5-8B9A-579DED3D9A95}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.StandAlone", "src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj", "{B6269AAC-170A-43D5-8B9A-579DED3D9A95}"
EndProject EndProject
@@ -36,6 +38,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.StandAlone.Net
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95} {B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {B6269AAC-170A-43D5-8B9A-579DED3D9A95}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NET452", "examples\WireMock.Net.ConsoleApplication\WireMock.Net.Console.NET452.csproj", "{668F689E-57B4-422E-8846-C0FF643CA268}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.WebApplication", "examples\WireMock.Net.WebApplication\WireMock.Net.WebApplication.csproj", "{049539C1-7A66-4559-AD7A-B1C73B97CBB0}"
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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.Proxy.NETCoreApp2", "examples\WireMock.Net.Console.Proxy.NETCoreApp2\WireMock.Net.Console.Proxy.NETCoreApp2.csproj", "{23A9AA3C-40FC-42AA-8A5E-05899795A1C6}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -74,6 +84,22 @@ Global
{668F689E-57B4-422E-8846-C0FF643CA999}.Debug|Any CPU.Build.0 = Debug|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.Debug|Any CPU.Build.0 = Debug|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.ActiveCfg = Release|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.ActiveCfg = Release|Any CPU
{668F689E-57B4-422E-8846-C0FF643CA999}.Release|Any CPU.Build.0 = Release|Any CPU {668F689E-57B4-422E-8846-C0FF643CA999}.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
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{049539C1-7A66-4559-AD7A-B1C73B97CBB0}.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
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -87,5 +113,12 @@ Global
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {EF242EDF-7133-4277-9A0C-18744DE08707} {B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {EF242EDF-7133-4277-9A0C-18744DE08707}
{10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A} {10E16614-61CA-48D8-8BDD-664C13913DED} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA999} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A} {668F689E-57B4-422E-8846-C0FF643CA999} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{668F689E-57B4-422E-8846-C0FF643CA268} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{049539C1-7A66-4559-AD7A-B1C73B97CBB0} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{26433A8F-BF01-4962-97EB-81BFFBB61096} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
{23A9AA3C-40FC-42AA-8A5E-05899795A1C6} = {F0C22C47-DF71-463C-9B04-B4E0F3B8708A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF428BCC-C837-433B-87D2-15C7014B73E9}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -21,7 +21,6 @@ environment:
before_build: before_build:
- dotnet restore .\src\WireMock.Net\WireMock.Net.csproj - dotnet restore .\src\WireMock.Net\WireMock.Net.csproj
- dotnet restore .\src\WireMock.Net.Standalone\WireMock.Net.Standalone.csproj - dotnet restore .\src\WireMock.Net.Standalone\WireMock.Net.Standalone.csproj
- nuget restore .\examples\WireMock.Net.ConsoleApplication\WireMock.Net.ConsoleApplication.csproj -PackagesDirectory packages
build_script: build_script:
# build WireMock.Net # build WireMock.Net
@@ -39,6 +38,6 @@ test_script:
- nuget.exe install coveralls.net -ExcludeVersion - nuget.exe install coveralls.net -ExcludeVersion
- pip install codecov - pip install codecov
- cmd: '"OpenCover\tools\OpenCover.Console.exe" -register:user -target:dotnet.exe -targetargs:"test test\WireMock.Net.Tests\WireMock.Net.Tests.csproj --no-build" -returntargetcode -filter:"+[WireMock.Net]* -[WireMock.Net.Tests*]*" -output:coverage.xml -oldstyle -searchdirs:".\test\WireMock.Net.Tests\bin\%CONFIGURATION%\net452"' - cmd: '"OpenCover\tools\OpenCover.Console.exe" -target:dotnet.exe -targetargs:"test test\WireMock.Net.Tests\WireMock.Net.Tests.csproj --no-build" -output:coverage.xml -returntargetcode -register:user -filter:"+[WireMock.Net]* -[WireMock.Net.Tests*]*" -nodefaultfilters -returntargetcode -oldstyle -searchdirs:".\test\WireMock.Net.Tests\bin\%CONFIGURATION%\net452"'
- codecov -f "coverage.xml" - codecov -f "coverage.xml"
- coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml - coveralls.net\tools\csmacnz.Coveralls.exe --opencover -i .\coverage.xml

View File

@@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="RestEase" Version="1.4.3" /> <PackageReference Include="RestEase" Version="1.4.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

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

View File

@@ -18,14 +18,27 @@
<Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json"> <Content Include="__admin\mappings\11111110-a633-40e8-a244-5cb80bc0ab66.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="__admin\mappings\826aff7c-6208-4a3c-923d-575248907db4.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" /> <ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" /> <PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\791a3f31-6946-4ce7-8e6f-0237c7443275.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\791a3f31-6946-4ce7-8e6f-0237c7443275.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -14,8 +14,9 @@
}, },
"Response": { "Response": {
"BodyAsJson": { "body": "static mapping" }, "BodyAsJson": { "body": "static mapping" },
"Headers": { "Headers": {
"Content-Type": "application/json" "Content-Type": "application/json",
} "Test-X": [ "test 1", "test 2" ]
}
} }
} }

View File

@@ -0,0 +1,36 @@
{
"Guid": "791a3f31-6946-4ce7-8e6f-0237c7443275",
"Title": "",
"Priority": 0,
"Request": {
"Path": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/proxy-google-test-post"
}
]
},
"Methods": [
"post"
],
"Body": {}
},
"Response": {
"StatusCode": 404,
"Body": "<!DOCTYPE html>\n<html lang=en>\n <meta charset=utf-8>\n <meta name=viewport content=\"initial-scale=1, minimum-scale=1, width=device-width\">\n <title>Error 404 (Not Found)!!1</title>\n <style>\n *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}\n </style>\n <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n <p><b>404.</b> <ins>Thats an error.</ins>\n <p>The requested URL <code>/proxy-google-test-post</code> was not found on this server. <ins>Thats all we know.</ins>\n",
"BodyAsBytes": "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ZW4+CiAgPG1ldGEgY2hhcnNldD11dGYtOD4KICA8bWV0YSBuYW1lPXZpZXdwb3J0IGNvbnRlbnQ9ImluaXRpYWwtc2NhbGU9MSwgbWluaW11bS1zY2FsZT0xLCB3aWR0aD1kZXZpY2Utd2lkdGgiPgogIDx0aXRsZT5FcnJvciA0MDQgKE5vdCBGb3VuZCkhITE8L3RpdGxlPgogIDxzdHlsZT4KICAgICp7bWFyZ2luOjA7cGFkZGluZzowfWh0bWwsY29kZXtmb250OjE1cHgvMjJweCBhcmlhbCxzYW5zLXNlcmlmfWh0bWx7YmFja2dyb3VuZDojZmZmO2NvbG9yOiMyMjI7cGFkZGluZzoxNXB4fWJvZHl7bWFyZ2luOjclIGF1dG8gMDttYXgtd2lkdGg6MzkwcHg7bWluLWhlaWdodDoxODBweDtwYWRkaW5nOjMwcHggMCAxNXB4fSogPiBib2R5e2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2Vycm9ycy9yb2JvdC5wbmcpIDEwMCUgNXB4IG5vLXJlcGVhdDtwYWRkaW5nLXJpZ2h0OjIwNXB4fXB7bWFyZ2luOjExcHggMCAyMnB4O292ZXJmbG93OmhpZGRlbn1pbnN7Y29sb3I6Izc3Nzt0ZXh0LWRlY29yYXRpb246bm9uZX1hIGltZ3tib3JkZXI6MH1AbWVkaWEgc2NyZWVuIGFuZCAobWF4LXdpZHRoOjc3MnB4KXtib2R5e2JhY2tncm91bmQ6bm9uZTttYXJnaW4tdG9wOjA7bWF4LXdpZHRoOm5vbmU7cGFkZGluZy1yaWdodDowfX0jbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzF4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7bWFyZ2luLWxlZnQ6LTVweH1AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4tcmVzb2x1dGlvbjoxOTJkcGkpeyNsb2dve2JhY2tncm91bmQ6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIG5vLXJlcGVhdCAwJSAwJS8xMDAlIDEwMCU7LW1vei1ib3JkZXItaW1hZ2U6dXJsKC8vd3d3Lmdvb2dsZS5jb20vaW1hZ2VzL2JyYW5kaW5nL2dvb2dsZWxvZ28vMngvZ29vZ2xlbG9nb19jb2xvcl8xNTB4NTRkcC5wbmcpIDB9fUBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKC13ZWJraXQtbWluLWRldmljZS1waXhlbC1yYXRpbzoyKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzJ4L2dvb2dsZWxvZ29fY29sb3JfMTUweDU0ZHAucG5nKSBuby1yZXBlYXQ7LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6MTAwJSAxMDAlfX0jbG9nb3tkaXNwbGF5OmlubGluZS1ibG9jaztoZWlnaHQ6NTRweDt3aWR0aDoxNTBweH0KICA8L3N0eWxlPgogIDxhIGhyZWY9Ly93d3cuZ29vZ2xlLmNvbS8+PHNwYW4gaWQ9bG9nbyBhcmlhLWxhYmVsPUdvb2dsZT48L3NwYW4+PC9hPgogIDxwPjxiPjQwNC48L2I+IDxpbnM+VGhhdOKAmXMgYW4gZXJyb3IuPC9pbnM+CiAgPHA+VGhlIHJlcXVlc3RlZCBVUkwgPGNvZGU+L3Byb3h5LWdvb2dsZS10ZXN0LXBvc3Q8L2NvZGU+IHdhcyBub3QgZm91bmQgb24gdGhpcyBzZXJ2ZXIuICA8aW5zPlRoYXTigJlzIGFsbCB3ZSBrbm93LjwvaW5zPgo=",
"BodyEncoding": {
"CodePage": 65001,
"EncodingName": "Unicode (UTF-8)",
"WebName": "utf-8"
},
"UseTransformer": false,
"Headers": {
"Date": "Wed, 27 Oct 2017 18:57:40 GMT",
"Alt-Svc": "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"",
"Referrer-Policy": "no-referrer",
"Connection": "close"
}
}
}

View File

@@ -0,0 +1,20 @@
<?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

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="info"
internalLogFile="c:\temp\wiremock-internal-nlog.log">
<targets>
<!-- write logs to file -->
<target xsi:type="File" name="all" fileName="c:\temp\wiremock-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId.Id}|${uppercase:${level}}|${logger}|${message} ${exception}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Debug" writeTo="all" />
</rules>
</nlog>

View File

@@ -0,0 +1,36 @@
using Newtonsoft.Json;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.Proxy.NETCoreApp2
{
class Program
{
static void Main(string[] args)
{
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091", "https://localhost:9443" },
StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
//ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true,
SaveMappingToFile = false,
BlackListedHeaders = new[] { "dnt", "Content-Length" }
}
});
server.LogEntriesChanged += (sender, eventRecordArgs) =>
{
System.Console.WriteLine(JsonConvert.SerializeObject(eventRecordArgs.NewItems, Formatting.Indented));
};
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
}
}
}

View File

@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:63377/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WireMock.Net.Console.Proxy.NETCoreApp2": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:63378/"
}
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
</Project>

View File

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

View File

@@ -0,0 +1,36 @@
using Newtonsoft.Json;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.Proxy.Net452
{
class Program
{
static void Main(string[] args)
{
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "https://www.google.com",
//ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true,
SaveMappingToFile = false,
BlackListedHeaders = new[] { "dnt", "Content-Length" }
}
});
server.LogEntriesChanged += (sender, eventRecordArgs) =>
{
System.Console.WriteLine(JsonConvert.SerializeObject(eventRecordArgs.NewItems, Formatting.Indented));
};
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
}
}
}

View File

@@ -0,0 +1,35 @@
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

@@ -0,0 +1,105 @@
<?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=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.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.StandAlone\WireMock.Net.StandAlone.csproj">
<Project>{b6269aac-170a-43d5-8b9a-579ded3d9a95}</Project>
<Name>WireMock.Net.StandAlone</Name>
</ProjectReference>
<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

@@ -0,0 +1,5 @@
<?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="10.0.3" targetFramework="net452" />
</packages>

View File

@@ -2,7 +2,7 @@
using WireMock.Server; using WireMock.Server;
using WireMock.Settings; using WireMock.Settings;
namespace WireMock.Net.Console.Record.NETCoreApp namespace WireMock.Net.Console.Proxy.NETCoreApp
{ {
static class Program static class Program
{ {
@@ -10,13 +10,16 @@ namespace WireMock.Net.Console.Record.NETCoreApp
{ {
var server = FluentMockServer.Start(new FluentMockServerSettings var server = FluentMockServer.Start(new FluentMockServerSettings
{ {
Urls = new[] { "http://localhost:9095/", "https://localhost:9096/" }, Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
StartAdminInterface = true, StartAdminInterface = true,
ReadStaticMappings = false,
ProxyAndRecordSettings = new ProxyAndRecordSettings ProxyAndRecordSettings = new ProxyAndRecordSettings
{ {
Url = "https://www.msn.com", Url = "https://www.google.com",
//X509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)", //ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
SaveMapping = true SaveMapping = true,
SaveMappingToFile = false,
BlackListedHeaders = new [] { "dnt", "Content-Length" }
} }
}); });

View File

@@ -7,12 +7,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommandLineArgumentsParser" Version="3.0.10" /> <ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" /> <Folder Include="__admin\mappings\" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
@@ -21,13 +20,85 @@ namespace WireMock.Net.ConsoleApplication
{ {
Urls = new[] { url1, url2, url3 }, Urls = new[] { url1, url2, url3 },
StartAdminInterface = true, StartAdminInterface = true,
ReadStaticMappings = true ReadStaticMappings = true,
WatchStaticMappings = true,
//ProxyAndRecordSettings = new ProxyAndRecordSettings
//{
// SaveMapping = true
//},
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); }
}); });
System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(" and ", server.Urls)); System.Console.WriteLine("FluentMockServer listening at {0}", string.Join(",", server.Urls));
server.SetBasicAuthentication("a", "b"); server.SetBasicAuthentication("a", "b");
// server.AllowPartialMapping(); server.AllowPartialMapping();
// .WithHeader("Stef", "Stef")
//server
// .Given(Request.Create().WithPath("*"))
// .RespondWith(Response.Create()
// .WithProxy("http://restcountries.eu"));
server
.Given(Request
.Create()
.WithPath("/jsonthings")
.WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"))
.UsingPut())
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""JsonPathMatcher !!!""}"));
server
.Given(Request
.Create()
.WithPath(new WildcardMatcher("/navision/OData/Company('My Company')/School*", true))
.WithParam("$filter", "(substringof(Code, 'WA')")
.UsingGet())
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""odata""}"));
server
.Given(Request.Create().WithPath("/headers", "/headers_test").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
//.WithHeader("MyHeader", "application/json", "application/json2")
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
server
.Given(Request.Create().WithPath("/file").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile(@"c:\temp\x.json", false)
);
server
.Given(Request.Create().WithPath("/filecache").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile(@"c:\temp\x.json")
);
server
.Given(Request.Create().WithPath("/file_rel").UsingGet())
.RespondWith(Response.Create()
.WithBodyFromFile("Program.cs", false)
);
server
.Given(Request.Create().WithHeader("ProxyThis", "true")
.UsingGet())
.RespondWith(Response.Create()
.WithProxy("http://www.google.com")
);
server
.Given(Request.Create().WithPath("/bodyasbytes.png")
.UsingGet())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "image/png")
.WithBody(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTczbp9jAAAAJ0lEQVQoU2NgUPuPD6Hz0RCEAtJoiAxpCCBXGgmRIo0TofORkdp/AMiMdRVnV6O0AAAAAElFTkSuQmCC"))
);
server server
.Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p")) .Given(Request.Create().WithPath("/oauth2/access").UsingPost().WithBody("grant_type=password;username=u;password=p"))
@@ -56,14 +127,7 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithStatusCode(201) .WithStatusCode(201)
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data posted with FUNC 201""}")); .WithBodyAsJson(new { result = "data posted with FUNC 201" }));
server
.Given(Request.Create().WithPath("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data posted with 201""}"));
server server
.Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"))) .Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")))

View File

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

View File

@@ -36,20 +36,22 @@
<ApplicationIcon>..\..\WireMock.Net-Logo.ico</ApplicationIcon> <ApplicationIcon>..\..\WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.8\lib\net45-full\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"> <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> <HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="SimMetrics.Net, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="SimMetrics.Net, Version=1.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.3\lib\net45\SimMetrics.Net.dll</HintPath> <HintPath>..\..\packages\SimMetrics.Net.1.0.4\lib\net45\SimMetrics.Net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="WireMock.Net"> <Reference Include="System.XML" />
<HintPath>..\..\src\WireMock.Net\bin\$(Configuration)\net45\WireMock.Net.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="MainApp.cs" /> <Compile Include="MainApp.cs" />
@@ -60,6 +62,9 @@
<None Include="App.config"> <None Include="App.config">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config"> <None Include="packages.config">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
@@ -67,6 +72,16 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj">
<Project>{b6269aac-170a-43d5-8b9a-579ded3d9a95}</Project>
<Name>WireMock.Net.StandAlone</Name>
</ProjectReference>
<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" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -0,0 +1,20 @@
<?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,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" /> <package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" /> <package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.3" targetFramework="net452" /> <package id="SimMetrics.Net" version="1.0.4" targetFramework="net452" />
</packages> </packages>

View File

@@ -1,21 +1,31 @@
using System; using System;
using System.IO;
using System.Reflection;
using System.Threading; using System.Threading;
using log4net;
using log4net.Config;
using log4net.Repository;
using WireMock.Server; using WireMock.Server;
namespace WireMock.Net.StandAlone.NETCoreApp namespace WireMock.Net.StandAlone.NETCoreApp
{ {
class Program static class Program
{ {
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
// private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
private static int sleepTime = 30000; private static int sleepTime = 30000;
private static FluentMockServer server; private static FluentMockServer _server;
static void Main(string[] args) static void Main(string[] args)
{ {
server = StandAloneApp.Start(args); XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
_server = StandAloneApp.Start(args, new WireMockLog4NetLogger());
Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down"); Console.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");
System.Console.CancelKeyPress += (s,e) => Console.CancelKeyPress += (s, e) =>
{ {
Stop("CancelKeyPress"); Stop("CancelKeyPress");
}; };
@@ -25,9 +35,9 @@ namespace WireMock.Net.StandAlone.NETCoreApp
Stop("AssemblyLoadContext.Default.Unloading"); Stop("AssemblyLoadContext.Default.Unloading");
}; };
while(true) while (true)
{ {
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server running"); Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server running : {_server.IsStarted}");
Thread.Sleep(sleepTime); Thread.Sleep(sleepTime);
} }
} }
@@ -35,7 +45,7 @@ namespace WireMock.Net.StandAlone.NETCoreApp
private static void Stop(string why) private static void Stop(string why)
{ {
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopping because '{why}'"); Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopping because '{why}'");
server.Stop(); _server.Stop();
Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopped"); Console.WriteLine($"{DateTime.UtcNow} WireMock.Net server stopped");
} }
} }

View File

@@ -6,8 +6,18 @@
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon> <ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" /> <ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,30 @@
using log4net;
using WireMock.Logging;
namespace WireMock.Net.StandAlone.NETCoreApp
{
internal class WireMockLog4NetLogger : IWireMockLogger
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
public void Debug(string formatString, params object[] args)
{
Log.DebugFormat(formatString, args);
}
public void Info(string formatString, params object[] args)
{
Log.InfoFormat(formatString, args);
}
public void Warn(string formatString, params object[] args)
{
Log.WarnFormat(formatString, args);
}
public void Error(string formatString, params object[] args)
{
Log.ErrorFormat(formatString, args);
}
}
}

View File

@@ -0,0 +1,20 @@
<?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,4 +1,6 @@
using System; using System;
using System.IO;
using log4net.Config;
namespace WireMock.Net.StandAlone.Net452 namespace WireMock.Net.StandAlone.Net452
{ {
@@ -6,6 +8,8 @@ namespace WireMock.Net.StandAlone.Net452
{ {
static void Main(params string[] args) static void Main(params string[] args)
{ {
XmlConfigurator.Configure(new FileInfo("log4net.config"));
StandAloneApp.Start(args); StandAloneApp.Start(args);
Console.WriteLine("Press any key to stop the server"); Console.WriteLine("Press any key to stop the server");

View File

@@ -39,6 +39,9 @@
<StartupObject>WireMock.Net.StandAlone.Net452.Program</StartupObject> <StartupObject>WireMock.Net.StandAlone.Net452.Program</StartupObject>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
@@ -50,6 +53,9 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1,20 @@
<?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,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
</packages> </packages>

View File

@@ -0,0 +1,22 @@
using Microsoft.Extensions.Logging;
namespace WireMock.Net.WebApplication
{
public class App
{
private readonly IWireMockService _service;
private readonly ILogger _logger;
public App(IWireMockService service, ILogger logger)
{
_service = service;
_logger = logger;
}
public void Run()
{
_logger.LogInformation("WireMock.Net App running");
_service.Run();
}
}
}

View File

@@ -0,0 +1,7 @@
namespace WireMock.Net.WebApplication
{
public interface IWireMockService
{
void Run();
}
}

View File

@@ -0,0 +1,57 @@
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WireMock.Settings;
namespace WireMock.Net.WebApplication
{
public class Program
{
public static void Main(string[] args)
{
// Create service collection
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
// Create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
// Run app
serviceProvider.GetService<App>().Run();
}
private static void ConfigureServices(IServiceCollection serviceCollection)
{
// Build configuration
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables() // <-- this is needed to to override settings via the Azure Portal App Settings
.Build();
// Add LoggerFactory
var factory = new LoggerFactory();
serviceCollection.AddSingleton(factory
.AddConsole(configuration.GetSection("Logging"))
.AddDebug()
.AddAzureWebAppDiagnostics()
);
serviceCollection.AddSingleton(factory.CreateLogger("WireMock.Net Logger"));
// Add access to generic IConfigurationRoot
serviceCollection.AddSingleton(configuration);
// Add access to IFluentMockServerSettings
var settings = configuration.GetSection("FluentMockServerSettings").Get<FluentMockServerSettings>();
serviceCollection.AddSingleton<IFluentMockServerSettings>(settings);
// Add services
serviceCollection.AddTransient<IWireMockService, WireMockService>();
// Add app
serviceCollection.AddTransient<App>();
}
}
}

View File

@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56513/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchUrl": "__admin/settings",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WireMock.Net.WebApplication": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "__admin/settings",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:56514/"
}
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.StandAlone\WireMock.Net.StandAlone.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,37 @@
using System.Threading;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using WireMock.Net.StandAlone;
using WireMock.Settings;
namespace WireMock.Net.WebApplication
{
public class WireMockService : IWireMockService
{
private static int sleepTime = 30000;
private readonly ILogger _logger;
private readonly IFluentMockServerSettings _settings;
public WireMockService(ILogger logger, IFluentMockServerSettings settings)
{
_logger = logger;
_settings = settings;
}
public void Run()
{
_logger.LogInformation("WireMock.Net server starting");
StandAloneApp.Start(_settings);
_logger.LogInformation($"WireMock.Net server settings {JsonConvert.SerializeObject(_settings)}");
while (true)
{
_logger.LogInformation("WireMock.Net server running");
Thread.Sleep(sleepTime);
}
}
}
}

View File

@@ -0,0 +1,20 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"LogLevel": {
"Default": "Debug"
}
}
},
"FluentMockServerSettings": {
"AdminUsername": "a",
"AdminPassword": "a",
"StartAdminInterface": true
}
}

View File

@@ -1,10 +1,9 @@
using System; using System.Linq;
using System.Linq;
using WireMock.Server; using WireMock.Server;
using WireMock.Settings; using WireMock.Settings;
using WireMock.Validation; using WireMock.Validation;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json; using WireMock.Logging;
namespace WireMock.Net.StandAlone namespace WireMock.Net.StandAlone
{ {
@@ -14,11 +13,11 @@ namespace WireMock.Net.StandAlone
public static class StandAloneApp public static class StandAloneApp
{ {
/// <summary> /// <summary>
/// Start WireMock.Net standalone based on the FluentMockServerSettings. /// Start WireMock.Net standalone Server based on the FluentMockServerSettings.
/// </summary> /// </summary>
/// <param name="settings">The FluentMockServerSettings</param> /// <param name="settings">The FluentMockServerSettings</param>
[PublicAPI] [PublicAPI]
public static FluentMockServer Start([NotNull] FluentMockServerSettings settings) public static FluentMockServer Start([NotNull] IFluentMockServerSettings settings)
{ {
Check.NotNull(settings, nameof(settings)); Check.NotNull(settings, nameof(settings));
@@ -26,16 +25,15 @@ namespace WireMock.Net.StandAlone
} }
/// <summary> /// <summary>
/// Start WireMock.Net standalone based on the commandline arguments. /// Start WireMock.Net standalone Server based on the commandline arguments.
/// </summary> /// </summary>
/// <param name="args">The commandline arguments</param> /// <param name="args">The commandline arguments</param>
/// <param name="logger">The logger</param>
[PublicAPI] [PublicAPI]
public static FluentMockServer Start([NotNull] string[] args) public static FluentMockServer Start([NotNull] string[] args, [CanBeNull] IWireMockLogger logger = null)
{ {
Check.NotNull(args, nameof(args)); Check.NotNull(args, nameof(args));
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
var parser = new SimpleCommandLineParser(); var parser = new SimpleCommandLineParser();
parser.Parse(args); parser.Parse(args);
@@ -43,6 +41,7 @@ namespace WireMock.Net.StandAlone
{ {
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true), StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"), ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping", true), AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping", true),
AdminUsername = parser.GetStringValue("AdminUsername"), AdminUsername = parser.GetStringValue("AdminUsername"),
AdminPassword = parser.GetStringValue("AdminPassword"), AdminPassword = parser.GetStringValue("AdminPassword"),
@@ -50,6 +49,11 @@ namespace WireMock.Net.StandAlone
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"), RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"),
}; };
if (logger != null)
{
settings.Logger = logger;
}
if (parser.Contains("Port")) if (parser.Contains("Port"))
{ {
settings.Port = parser.GetIntValue("Port"); settings.Port = parser.GetIntValue("Port");
@@ -66,15 +70,17 @@ namespace WireMock.Net.StandAlone
{ {
Url = proxyURL, Url = proxyURL,
SaveMapping = parser.GetBoolValue("SaveMapping"), SaveMapping = parser.GetBoolValue("SaveMapping"),
X509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("X509Certificate2ThumbprintOrSubjectName") SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
ClientX509Certificate2ThumbprintOrSubjectName = parser.GetStringValue("ClientX509Certificate2ThumbprintOrSubjectName"),
BlackListedHeaders = parser.GetValues("BlackListedHeaders")
}; };
} }
Console.WriteLine("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented)); settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
FluentMockServer server = Start(settings); FluentMockServer server = Start(settings);
Console.WriteLine("WireMock.Net server listening at {0}", string.Join(" and ", server.Urls)); settings.Logger.Info("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
return server; return server;
} }

View File

@@ -1,27 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description> <Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle> <AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.2.4</Version> <Version>1.0.3.4</Version>
<Authors>Stef Heyenrath</Authors> <Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<!-- <TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> -->
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.StandAlone</AssemblyName> <AssemblyName>WireMock.Net.StandAlone</AssemblyName>
<PackageId>WireMock.Net.StandAlone</PackageId> <PackageId>WireMock.Net.StandAlone</PackageId>
<PackageTags>tdd;mock;http;wiremock;test;server;unittest</PackageTags> <PackageTags>tdd;mock;http;wiremock;test;server;unittest</PackageTags>
<PackageReleaseNotes></PackageReleaseNotes> <PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl> <PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl> <PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/LICENSE</PackageLicenseUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl> <RepositoryUrl>https://github.com/WireMock-Net/WireMock.Net</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<DebugType>portable</DebugType>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon> <ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
<RootNamespace>WireMock.Net.StandAlone</RootNamespace> <RootNamespace>WireMock.Net.StandAlone</RootNamespace>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>full</DebugType>
<IncludeSource>True</IncludeSource>
<IncludeSymbols>True</IncludeSymbols>
<PathMap>$(MSBuildProjectDirectory)=/</PathMap>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard2.0' "> <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>NETSTANDARD</DefineConstants> <DefineConstants>NETSTANDARD</DefineConstants>
@@ -31,10 +36,6 @@
<PackageReference Include="JetBrains.Annotations" Version="10.4.0"> <PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>
</PackageReference> </PackageReference>
<!-- <PackageReference Include="CommandLineArgumentsParser" Version="3.0.16" /> -->
<!-- <PackageReference Include="Marsonsoft.CommandLineParser" Version="1.0.34" /> -->
<!-- <PackageReference Include="BurnSystems.CommandLine" Version="1.1.0" /> -->
<!-- <ProjectReference Include="..\..\..\CommandLineParser\src\CommandLineArgumentsParser\CommandLineArgumentsParser.csproj" /> -->
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -10,29 +10,20 @@ namespace WireMock.Admin.Mappings
/// <summary> /// <summary>
/// Gets or sets the unique identifier. /// Gets or sets the unique identifier.
/// </summary> /// </summary>
/// <value>
/// The unique identifier.
/// </value>
public Guid? Guid { get; set; } public Guid? Guid { get; set; }
/// <summary> /// <summary>
/// Gets or sets the unique title.
/// </summary>
/// <value>
/// The unique title. /// The unique title.
/// </value> /// </summary>
public string Title { get; set; } public string Title { get; set; }
/// <summary> /// <summary>
/// Gets or sets the priority.
/// </summary>
/// <value>
/// The priority. /// The priority.
/// </value> /// </summary>
public int? Priority { get; set; } public int? Priority { get; set; }
/// <summary> /// <summary>
/// Scenario. /// The Scenario.
/// </summary> /// </summary>
public string Scenario { get; set; } public string Scenario { get; set; }
@@ -48,19 +39,13 @@ namespace WireMock.Admin.Mappings
public object SetStateTo { get; set; } public object SetStateTo { get; set; }
/// <summary> /// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>
/// The request. /// The request.
/// </value> /// </summary>
public RequestModel Request { get; set; } public RequestModel Request { get; set; }
/// <summary> /// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response. /// The response.
/// </value> /// </summary>
public ResponseModel Response { get; set; } public ResponseModel Response { get; set; }
} }
} }

View File

@@ -10,79 +10,71 @@ namespace WireMock.Admin.Mappings
/// <summary> /// <summary>
/// Gets or sets the HTTP status. /// Gets or sets the HTTP status.
/// </summary> /// </summary>
/// <value>
/// The HTTP status.
/// </value>
public int? StatusCode { get; set; } public int? StatusCode { get; set; }
/// <summary>
/// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public string Body { get; set; } public string Body { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body.
/// </summary> /// </summary>
/// <value> public string BodyFromBase64 { get; set; }
/// The body.
/// </value>
public string BodyAsBase64 { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body (as JSON object). /// Gets or sets the body (as JSON object).
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public object BodyAsJson { get; set; } public object BodyAsJson { get; set; }
/// <summary>
/// Gets or sets the body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body as a file.
/// </summary>
public string BodyAsFile { get; set; }
/// <summary>
/// Is the body as file cached?
/// </summary>
public bool? BodyAsFileIsCached { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body encoding. /// Gets or sets the body encoding.
/// </summary> /// </summary>
/// <value>
/// The body encoding.
/// </value>
public EncodingModel BodyEncoding { get; set; } public EncodingModel BodyEncoding { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [use transformer]. /// Gets or sets a value indicating whether [use transformer].
/// </summary> /// </summary>
/// <value>
/// <c>true</c> if [use transformer]; otherwise, <c>false</c>.
/// </value>
public bool UseTransformer { get; set; } public bool UseTransformer { get; set; }
/// <summary> /// <summary>
/// Gets or sets the headers. /// Gets or sets the headers.
/// </summary> /// </summary>
/// <value> public IDictionary<string, object> Headers { get; set; }
/// The headers.
/// </value>
public IDictionary<string, string> Headers { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Headers (Raw). /// Gets or sets the Headers (Raw).
/// </summary> /// </summary>
/// <value>
/// The Headers (Raw).
/// </value>
public string HeadersRaw { get; set; } public string HeadersRaw { get; set; }
/// <summary> /// <summary>
/// Gets or sets the delay in milliseconds. /// Gets or sets the delay in milliseconds.
/// </summary> /// </summary>
/// <value>
/// The delay in milliseconds.
/// </value>
public int? Delay { get; set; } public int? Delay { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Proxy URL. /// Gets or sets the Proxy URL.
/// </summary> /// </summary>
/// <value>ProxyUrl</value>
public string ProxyUrl { get; set; } public string ProxyUrl { get; set; }
/// <summary> /// <summary>

View File

@@ -8,51 +8,33 @@ namespace WireMock.Admin.Requests
public class LogEntryModel public class LogEntryModel
{ {
/// <summary> /// <summary>
/// Gets or sets the unique identifier.
/// </summary>
/// <value>
/// The unique identifier. /// The unique identifier.
/// </value> /// </summary>
public Guid Guid { get; set; } public Guid Guid { get; set; }
/// <summary> /// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>
/// The request. /// The request.
/// </value> /// </summary>
public LogRequestModel Request { get; set; } public LogRequestModel Request { get; set; }
/// <summary> /// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response. /// The response.
/// </value> /// </summary>
public LogResponseModel Response { get; set; } public LogResponseModel Response { get; set; }
/// <summary> /// <summary>
/// Gets or sets the mapping unique identifier.
/// </summary>
/// <value>
/// The mapping unique identifier. /// The mapping unique identifier.
/// </value> /// </summary>
public Guid? MappingGuid { get; set; } public Guid? MappingGuid { get; set; }
/// <summary> /// <summary>
/// Gets or sets the mapping unique title.
/// </summary>
/// <value>
/// The mapping unique title. /// The mapping unique title.
/// </value> /// </summary>
public string MappingTitle { get; set; } public string MappingTitle { get; set; }
/// <summary> /// <summary>
/// Gets or sets the request match result.
/// </summary>
/// <value>
/// The request match result. /// The request match result.
/// </value> /// </summary>
public LogRequestMatchModel RequestMatchResult { get; set; } public LogRequestMatchModel RequestMatchResult { get; set; }
} }
} }

View File

@@ -11,74 +11,63 @@ namespace WireMock.Admin.Requests
public class LogRequestModel public class LogRequestModel
{ {
/// <summary> /// <summary>
/// Gets the Client IP Address. /// The Client IP Address.
/// </summary> /// </summary>
public string ClientIP { get; set; } public string ClientIP { get; set; }
/// <summary> /// <summary>
/// Gets the DateTime. /// The DateTime.
/// </summary> /// </summary>
public DateTime DateTime { get; set; } public DateTime DateTime { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Path.
/// </summary>
/// <value>
/// The Path. /// The Path.
/// </value> /// </summary>
public string Path { get; set; } public string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the absolete URL. ///The absolete URL.
/// </summary> /// </summary>
/// <value>
/// The absolute URL.
/// </value>
public string AbsoluteUrl { get; set; } public string AbsoluteUrl { get; set; }
/// <summary> /// <summary>
/// Gets the query. /// The query.
/// </summary> /// </summary>
public IDictionary<string, WireMockList<string>> Query { get; set; } public IDictionary<string, WireMockList<string>> Query { get; set; }
/// <summary> /// <summary>
/// Gets or sets the method.
/// </summary>
/// <value>
/// The method. /// The method.
/// </value> /// </summary>
public string Method { get; set; } public string Method { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Headers.
/// </summary>
/// <value>
/// The Headers. /// The Headers.
/// </value> /// </summary>
public IDictionary<string, string> Headers { get; set; } public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Cookies. /// Tthe Cookies.
/// </summary> /// </summary>
/// <value>
/// The Cookies.
/// </value>
public IDictionary<string, string> Cookies { get; set; } public IDictionary<string, string> Cookies { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// The body (as string).
/// </summary> /// </summary>
/// <value>
/// The body.
/// </value>
public string Body { get; set; } public string Body { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body encoding. /// The body (as JSON object).
/// </summary> /// </summary>
/// <value> public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// The body encoding. /// The body encoding.
/// </value> /// </summary>
public EncodingModel BodyEncoding { get; set; } public EncodingModel BodyEncoding { get; set; }
} }
} }

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Util;
namespace WireMock.Admin.Requests namespace WireMock.Admin.Requests
{ {
@@ -16,13 +17,38 @@ namespace WireMock.Admin.Requests
/// <summary> /// <summary>
/// Gets the headers. /// Gets the headers.
/// </summary> /// </summary>
public IDictionary<string, string> Headers { get; set; } public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// <summary> /// <summary>
/// Gets or sets the body. /// Gets or sets the body destination (SameAsSource, String or Bytes).
/// </summary>
public string BodyDestination { get; set; }
/// <summary>
/// The body (as string).
/// </summary> /// </summary>
public string Body { get; set; } public string Body { get; set; }
/// <summary>
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets or sets the body as file.
/// </summary>
public string BodyAsFile { get; set; }
/// <summary>
/// Is the body as file cached?
/// </summary>
public bool? BodyAsFileIsCached { get; set; }
/// <summary> /// <summary>
/// Gets or sets the original body. /// Gets or sets the original body.
/// </summary> /// </summary>

View File

@@ -55,6 +55,7 @@ namespace WireMock.Client
/// </summary> /// </summary>
/// <param name="mapping">MappingModel</param> /// <param name="mapping">MappingModel</param>
[Post("__admin/mappings")] [Post("__admin/mappings")]
[Header("Content-Type", "application/json")]
Task<string> PostMappingAsync([Body] MappingModel mapping); Task<string> PostMappingAsync([Body] MappingModel mapping);
/// <summary> /// <summary>
@@ -103,7 +104,7 @@ namespace WireMock.Client
/// </summary> /// </summary>
/// <returns>LogRequestModels</returns> /// <returns>LogRequestModels</returns>
[Get("__admin/requests")] [Get("__admin/requests")]
Task<IList<LogRequestModel>> GetRequestsAsync(); Task<IList<LogEntryModel>> GetRequestsAsync();
/// <summary> /// <summary>
/// Delete all requests. /// Delete all requests.
@@ -123,7 +124,7 @@ namespace WireMock.Client
/// <param name="guid">The Guid</param> /// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns> /// <returns>MappingModel</returns>
[Get("__admin/requests/{guid}")] [Get("__admin/requests/{guid}")]
Task<LogRequestModel> GetRequestAsync([Path] Guid guid); Task<LogEntryModel> GetRequestAsync([Path] Guid guid);
/// <summary> /// <summary>
/// Delete a request based on the guid /// Delete a request based on the guid
@@ -137,6 +138,25 @@ namespace WireMock.Client
/// </summary> /// </summary>
/// <param name="model">The RequestModel</param> /// <param name="model">The RequestModel</param>
[Post("__admin/requests/find")] [Post("__admin/requests/find")]
Task<IList<LogRequestModel>> FindRequestsAsync([Body] RequestModel model); [Header("Content-Type", "application/json")]
Task<IList<LogEntryModel>> FindRequestsAsync([Body] RequestModel model);
/// <summary>
/// Get all scenarios
/// </summary>
[Get("__admin/scenarios")]
Task<string> GetScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Delete("__admin/scenarios")]
Task<string> DeleteScenariosAsync();
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("__admin/scenarios")]
Task<string> ResetScenariosAsync();
} }
} }

View File

@@ -1,62 +0,0 @@
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Validation;
using WireMock.Settings;
namespace WireMock
{
internal class DynamicResponseProvider : IResponseProvider
{
private readonly Func<RequestMessage, ResponseMessage> _responseMessageFunc;
public DynamicResponseProvider([NotNull] Func<RequestMessage, ResponseMessage> responseMessageFunc)
{
Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
_responseMessageFunc = responseMessageFunc;
}
public Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMessage)
{
return Task.FromResult(_responseMessageFunc(requestMessage));
}
}
internal class DynamicAsyncResponseProvider : IResponseProvider
{
private readonly Func<RequestMessage, Task<ResponseMessage>> _responseMessageFunc;
public DynamicAsyncResponseProvider([NotNull] Func<RequestMessage, Task<ResponseMessage>> responseMessageFunc)
{
Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
_responseMessageFunc = responseMessageFunc;
}
public Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMessage)
{
return _responseMessageFunc(requestMessage);
}
}
internal class ProxyAsyncResponseProvider : IResponseProvider
{
private readonly Func<RequestMessage, ProxyAndRecordSettings, Task<ResponseMessage>> _responseMessageFunc;
private readonly ProxyAndRecordSettings _settings;
public ProxyAsyncResponseProvider([NotNull] Func<RequestMessage, ProxyAndRecordSettings, Task<ResponseMessage>> responseMessageFunc, [NotNull] ProxyAndRecordSettings settings)
{
Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
Check.NotNull(settings, nameof(settings));
_responseMessageFunc = responseMessageFunc;
_settings = settings;
}
public Task<ResponseMessage> ProvideResponseAsync(RequestMessage requestMessage)
{
return _responseMessageFunc(requestMessage, _settings);
}
}
}

View File

@@ -1,87 +1,137 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.HttpsCertificate;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock.Http namespace WireMock.Http
{ {
internal static class HttpClientHelper internal static class HttpClientHelper
{ {
public static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
private static HttpClient CreateHttpClient(string clientX509Certificate2ThumbprintOrSubjectName = null)
{ {
#if NETSTANDARD || NET46
var handler = new HttpClientHandler
{
CheckCertificateRevocationList = false,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
#else
var handler = new WebRequestHandler
{
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
#endif
if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName)) if (!string.IsNullOrEmpty(clientX509Certificate2ThumbprintOrSubjectName))
{ {
#if NETSTANDARD || NET46 handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName); var x509Certificate2 = ClientCertificateHelper.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2); handler.ClientCertificates.Add(x509Certificate2);
#else
var handler = new WebRequestHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var x509Certificate2 = CertificateUtil.GetCertificate(clientX509Certificate2ThumbprintOrSubjectName);
handler.ClientCertificates.Add(x509Certificate2);
return new HttpClient(handler);
#endif
} }
return new HttpClient(); // For proxy we shouldn't follow auto redirects
handler.AllowAutoRedirect = false;
// If UseCookies enabled, httpClient ignores Cookie header
handler.UseCookies = false;
var client = new HttpClient(handler);
#if NET452 || NET46
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
#endif
return client;
} }
public static async Task<ResponseMessage> SendAsync(RequestMessage requestMessage, string url, string clientX509Certificate2ThumbprintOrSubjectName = null) public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url)
{ {
var client = CreateHttpClient(clientX509Certificate2ThumbprintOrSubjectName); Check.NotNull(client, nameof(client));
Check.NotNull(requestMessage, nameof(requestMessage));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url); var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
WireMockList<string> contentTypeHeader = null;
bool contentTypeHeaderPresent = requestMessage.Headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase));
if (contentTypeHeaderPresent)
{
contentTypeHeader = requestMessage.Headers[HttpKnownHeaderNames.ContentType];
}
// Set Body if present
if (requestMessage.BodyAsBytes != null)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
else if (requestMessage.BodyAsJson != null)
{
httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(requestMessage.BodyAsJson), requestMessage.BodyEncoding);
}
else if (requestMessage.Body != null)
{
httpRequestMessage.Content = new StringContent(requestMessage.Body, requestMessage.BodyEncoding);
}
// Overwrite the host header // Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority; httpRequestMessage.Headers.Host = requiredUri.Authority;
// Set headers if present // Set headers if present
if (requestMessage.Headers != null) if (requestMessage.Headers != null)
{ {
foreach (var headerName in requestMessage.Headers.Keys.Where(k => k.ToUpper() != "HOST")) foreach (var header in requestMessage.Headers.Where(header => !string.Equals(header.Key, "HOST", StringComparison.OrdinalIgnoreCase)))
{ {
httpRequestMessage.Headers.Add(headerName, new[] { requestMessage.Headers[headerName] }); // Try to add to request headers. If failed - try to add to content headers
if (!httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
{
httpRequestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
} }
} }
// Set Body if present
if (requestMessage.BodyAsBytes != null && requestMessage.BodyAsBytes.Length > 0)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
// Call the URL // Call the URL
var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead); var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
// Create transform response
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
// Transform response // Set both content and response headers, replacing URLs in values
var responseMessage = new ResponseMessage var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>()).ToArray();
if (httpResponseMessage.Content != null)
{ {
StatusCode = (int)httpResponseMessage.StatusCode, var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
Body = await httpResponseMessage.Content.ReadAsStringAsync() var body = await BodyParser.Parse(stream, contentTypeHeader?.FirstOrDefault());
}; responseMessage.Body = body.BodyAsString;
responseMessage.BodyAsJson = body.BodyAsJson;
responseMessage.BodyAsBytes = body.BodyAsBytes;
}
foreach (var header in httpResponseMessage.Headers) foreach (var header in headers)
{ {
responseMessage.AddHeader(header.Key, header.Value.FirstOrDefault()); // If Location header contains absolute redirect URL, and base URL is one that we proxy to,
// we need to replace it to original one.
if (string.Equals(header.Key, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase)
&& Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri)
&& string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase))
{
var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery);
responseMessage.AddHeader(header.Key, replacedLocationUri.ToString());
}
else
{
responseMessage.AddHeader(header.Key, header.Value.ToArray());
}
} }
return responseMessage; return responseMessage;

View File

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

View File

@@ -5,18 +5,15 @@ using System.Text.RegularExpressions;
namespace WireMock.Http namespace WireMock.Http
{ {
/// <summary> /// <summary>
/// Utility class /// Port Utility class
/// </summary> /// </summary>
public static class PortUtil public static class PortUtil
{ {
private static readonly Regex UrlDetailsRegex = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>\d+)?/", RegexOptions.Compiled); private static readonly Regex UrlDetailsRegex = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>\d+)?/", RegexOptions.Compiled);
/// <summary> /// <summary>
/// The find free TCP port. /// Finds a free TCP port.
/// </summary> /// </summary>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
/// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net.</remarks> /// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net.</remarks>
public static int FindFreeTcpPort() public static int FindFreeTcpPort()
{ {
@@ -40,7 +37,7 @@ namespace WireMock.Http
public static bool TryExtractProtocolAndPort(string url, out string proto, out int port) public static bool TryExtractProtocolAndPort(string url, out string proto, out int port)
{ {
proto = null; proto = null;
port = -1; port = 0;
Match m = UrlDetailsRegex.Match(url); Match m = UrlDetailsRegex.Match(url);
if (m.Success) if (m.Success)

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
namespace WireMock.Http namespace WireMock.HttpsCertificate
{ {
internal static class CertificateUtil internal static class ClientCertificateHelper
{ {
public static X509Certificate2 GetCertificate(string thumbprintOrSubjectName) public static X509Certificate2 GetCertificate(string thumbprintOrSubjectName)
{ {

View File

@@ -0,0 +1,91 @@
using System;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
{
internal static class PublicCertificateHelper
{
// 1] Generate using https://www.pluralsight.com/blog/software-development/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net
// 2] Converted to Base64
private const string Data = @"MIIQMgIBAzCCD+4GCSqGSIb3DQEHAaCCD98Egg/bMIIP1zCCCogGCSqGSIb3DQEHAaCCCnkEggp1
MIIKcTCCCm0GCyqGSIb3DQEMCgECoIIJfjCCCXowHAYKKoZIhvcNAQwBAzAOBAi1j9x1jTfUewIC
B9AEgglYa48lP16+isiGEVT7zwN3XwaPwPOHZcQ7tRA/DA8LZnZbwU7XhtPObF5bZcHn4engX2An
ISFpe2S5XJ7BfHmsGOO7Bxj6C2IcZIPTefvAd9vWE0WUAGN11SLhJ3fB/ZRt3Nys7JCJzywQCkYK
dCA35V7WfETCLT6+ArtRU4qsjop2YXyUzcLw3OuumBAoRsazgUKz8rkZJbifkSikbdxs+Hupcf2I
NOOuKStKoqouqCO/vmRi8u8g0KQhf2LcQBSqLk6OZ8TQuv07W5tVO2Ky5qCYu6aXBBlHhGSY9fGL
vqaYcxMcVJQpXUUL6nSWCoaLdaAAB+Anw1Tpbd47W7ieTK5Yq2IROPQIr1mk8nvFbxoTcBuIQ6oU
RiiLX+mb3hYgbTL3LqDmmm9FFI8enJu6pUxP8iKKROtCqhYXhF1i3EwReBzJzpDGZ+y4rJxb0Es4
sPVc/TaVPSJCTmgcKzwps7M12uxm8G9Dv3lKgZVmgDRivovCJFxHdCdgCYB08FvNWuFtXO+schsE
N0nY2i07A2joaJC18yvoNGZ+ySBTBPOBN+5XbiQs0vsQ4MfLETb2O2dFjwE/tErgo6RWYg2qQNAe
DSh2wHzI0YJM3PqaUR0Q9KnjEWc92hsLI34KnuNkNkVk4NEjPOetxeIBcYN7CDD6tTxp42sU++bT
o9zyjy1BPS+LuEblxDTSlVPb0dxvkwNBXBi0RXIOWfD15BWcV1Uv972jB6To1XPDIOc+eq7fa5yn
HRW/GYdGPmOYKietdw6V3t2Et9cPlw4v08IelucF06Ju2a73QtidtkA89vxjn7qOEVACAXpsiMsM
4JCcAzF7jh0U2mskSB14I9HcZh1Sei0J2ZULcXNyuIw9nsWp8vrH04OOoUDe7/UpX7c8+A+tqDUy
1W2V1dJDhlwu2SXL5jJFBK4P9p2e+XyHJ+AcYXrHQIKxqoCgvnywT4HnI2bvZ1+lmIR99mp1Cvzj
RUgJaqhI7u6WH3i6fmkA92hF8MP5WDYTGwjsHPrCg6Xkqykuvub4osu+gLq5t+JC9rOczgrRNYXg
54FMzlCyQxTfgY6IRwPH/xYHKGbViFF+jA4ksLMRjI2XOV4swbI232SxMoQQDNsjx1la2nZM3P5z
g7zpmaiyzY44q3kU1viMMR7qM/w1S6nTW0ZkzTXk8Gttor/0JWT1K8KgwK02B6Q9zNwfK60a0cQm
SbA/dXkWapuIzQLz+ZUPyG/1EP5KuKNnsp0hfVi8TTgOFceoV9kyIhrTQNI0o5O91dqkyWd/bMl2
OnrnRnhka6f839zJKUpWPTfRX9RMJTk/5HVcL/qsHYcJedZyPawJjMU+cxW1ZZjr1Lo6M0fjKuTI
Askg0ZKS0FJ60jTKnc1DmldQLtieHh1UTdty+yn1A0rGnrFEyN7if2/d1EduWJaf6bvWzfH+d/36
1gDwp4OXi0qWu7c5zByGZi2j2sFo4v0cGgjPZUJvF5z0V8OkE15DiA4xtTSkIjCnEmOhODViwrfc
ONvHB+inBW9wLp26qFgNcYrYxP2FC54pPCxO+KJaAJrtfE3A4lkboB7V0xFu23ecOy4n2gho39tg
Bxkt1Xj3GCLgeKvcYLzOPytZldXDTtoCcsm5uhCmBHEmPUsnLc7Tt1cFflFtWTOjtyv0Lk8Qu2BU
B/hSSgjZRpqE+hzjtghjXdFOT5wKULvtUz5eu+lH7kjGghQbF962vLcRCsr+tMPba6MFqhy5Q+dM
NcHc+HIx2WiuRZ6jdCZSUpH3f1+kH6XYj2P3/F0kLBRAMPGKbXpIi9Px4AVDEDClL77mDpVgeEoh
kkVh5zvk2PsEPonmTFK0kQE8Q4cYFWTKa9lAE4Wc35EzvpKFdTwQKhr5kN7tEq17n5wJt/499164
ho0+LjzYy62JI/fv3RPISL0gXr2INLW7fgZ5KNjcnu/AITJu3ycw/XH8BKsx4dcbBgBdrKY8afEn
IZ1EIv/TuNvmifmAEGX/DWuVmZIOU6pTystzTQwfz0wko3lUKjkPM40RLN9o6lddV6fM3QNtK0ac
hqOOmG68LzI1U33nvUBol/FeEV0DLvGjvsIRC/TCtDu5Vk2tKS13p9kNj4owJK8d343PZ/eyi/Oe
sNZCCJJuj4iIodekm1hzj7zc6ZLNudgab/WkF7TbWDOhDPwG1gE/McffGNWPFlwsaopoZaH8E8tl
QSOnHqAiNa7B3ifxMrGDWHDlxkWddClbKd9ujL4mgB88Wo8JceLawDOcSVGImvWGxsrK2RX7FK57
GQYuc0zcq3NH4jpoOyS+vpMeigTPDOvQdqjGgEUW3aXdA8Ma0KYVEyAhK/rFXw8FelGREM2ku1kN
kziOTAe52SWqcrv6NUPfo1/Uc6u7KpwQrcDlFZWxPCKomeRQTm6AmP2QHMgl2gaUbmuBF/C9Ccl2
1Iqh8vUdDT3lHdf5I5SjRPJJXX2/0/oUFmwIC5AFp8/XXnIG05BER1X2Y+SL15QHW7lYsvd4ZKTv
tvYaZNWajgAVZl8gJYFUQG+U+cFYcpHhf6SGzcuwcmQJGxptZAVnRtDzNjJ04vJB616/uoI2Qkp2
ysGAjDNlwgeckmU7TSYoYaML29pRupTTQqKItyFDuebUpSKBTxsEFIJBCTErA8TD8I9T5nzT+rTy
+Lpp9mqcxQR1RhxgTx5bE7D4igdblobX0IONARg4EIAk8xj1Ba3k4skdjAQcJOHKd+xVo+vsrIqg
a+ycemROE5F3D3s21ozMOn1Dy8iIeQusJQTSkP82+wHYWXRg59N0cq/40CaJskK+yp7afOWFoCqY
T/D9OGlfeIIiLivwMh8naPZyM4+pd/CFZwcWoGtIno04nWWR/xQVe17jqPMov1xonC2E3AcKxUXl
PMdZoOARkR+KHZnoBZ/vjqxeDPARKupijkw5QQI3jNmd5IELjcL8OraHlo+e884mRsa/66J7p94D
bidzjiVLUhCsZnVks9eZF6PIEg49eq/+w8ph3X7XBNnZYAbgola/0yy/PlPzgJ3p/AgXMoGr+HXO
p2WAs1WRo9mAdeOBMrAMvXKFD04bZPNHke0Ri03O5U7NRRs1T0LnqdZHyF39As8FiktfJl1bn/U0
sUjhc4fDNnDaBN8VF8VsEa7UolRC6NqQ1oHaeEZRoq0li6NbXIXdxIIT4bbqwajqFkvvO6qc6SEG
iAlUzTGB2zATBgkqhkiG9w0BCRUxBgQEAQAAADBXBgkqhkiG9w0BCRQxSh5IADcAOAA1ADAAZABj
ADAAYwAtAGIAZQBmAGIALQA0AGEANQBiAC0AOAA5ADcAMAAtAGIAZAA5ADkAOQAxADEAOQA2AGIA
YgA1MGsGCSsGAQQBgjcRATFeHlwATQBpAGMAcgBvAHMAbwBmAHQAIABFAG4AaABhAG4AYwBlAGQA
IABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByACAAdgAxAC4AMDCC
BUcGCSqGSIb3DQEHBqCCBTgwggU0AgEAMIIFLQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMwDgQI
Amt1zAZpKWkCAgfQgIIFAJoBLiXPEZGuUfsyM2ed66sBIirBctHbhyydZsQDT8V2crq6AI3P0dBT
Agf/MouK/JcAfdGEEpU6SKxqZBDZoTRbyK7VdW5YiKGUurFGf66L9K3c4MHhVLMWnSkwK+0gwiIB
RB82Or4ru0cSQbF32vsuJgJY9Ax4YODKokPFUzZjPrmch4AgZWKxslDFDq4xs3tpLIeZbALWYdrR
PUZaReO+NaLfNKwTZsinzjPkCst7R1Jfjf1abikPrOMPgYFUiQL7GNQFbefeJu9SCXlj09u/qw+l
uLrwEyMamG0cgjrWbMOohGtvAuHqeZIIWuLnGE2quq7Ah/U55lliZn3IFgs1n6FalW/XGH0T0aRA
im6f1EgxtJShBNdG6qNrkzYMyY2Xvpk82qtmvMbhJMDstpovsdT1rZ6OGfsyJAlG94BcCWC2wuvW
MYs6H7AirBG/iocNm7JwSBQ7wjl0keH9vuHDQsI+uu9yWGuyZK6MmxDEOEMZRndU0GrlLIp7zQx8
gPeagKqSHhPK0ghHhDilMyToE3Euvi5jneh90eofWK6E4E8KtQTWvFeCe9fYRhMaflH9lwfHfXPo
9J+7GZLRF/MDTlE8jzWoP5csUxV3jnXQkTUOfHvO7QK6POKwLGkCyZ5wKFydyYdTekG+KU2Vml2y
s6pZ+kME1VMYiHRF3CaXX1ZYKikEdnuB1Qp8BE2uKQTaYO4Wns0vQIVRWTrk/Gp5RXu1ihzoTiFb
YqLFROQTM+dVTUk3C6W82OroNwofW5ErZwpbdgJJ83gbPLr9W4KZ6YegvEWFT1MawnIYDC6RSKtg
fI1blSZOo1SIF6+nR0gFPivSEGBJHclIg7TtvGSB1q7TQFS4W5l+AHdgGPqqURnjuJ7/DVFZHqEV
jJM1QEvH/RY1rDXP8FZC6CZR/Le7tVm5o8bHnlU4gyStvNyLXHCP6o3gHmaBcfYmqJr/0ZEKnwnd
MBmdIgwQ3+JnKvjAeDe8Z/l0U03CbzeyN3TgUolDlUGVDF2FdPZqrVsLKw6VJv3hoFZmgEbb1fDq
Jblc82lrYIEW8E7ltRLDyNDmRdyaqkqw0e7SygXXxv6SKerxoJ5E1NyJdHeQXSahRrsj5UZpxlTE
ylb3upIF0F006w2D5J7xUDktPetVgM97dN3whbOrzWPPkn5CTZMaUdYGTYQK3/K/jQSKuXcaM04A
EWmcQOQ/5Quco/aMYWTTwFI9+bKZayZKHqQjNKuwss+iWTW2b26cA2XAr2XWCL9PEybVRK/5n4km
5qkGIMjjczZxNy1+H1QoEOwkGVzQd390ktQajJBFcf9wBO+Ar14EgPKvdL4DRvCvXOK3CtrgbAq6
GK7uULRrz9t/5lu27ba5wcwxg6bFhgCsJsoSCJnLCR7H+QMB4LhnWA10U4hFWCamCKFoGkiXW6yV
OF4x+0D0MmrjrrAGi05KzfrsXNtRG0xbkmvrsjqzmsOKyjvtiBCrR0S6NUtKhyxoiz5bCCm+d8rm
jaPk9q01k52pjJAKYW0f+5+r15LamBecnjXtJ07LCl6cMA1Cj4L0mQUSefyFi666GC3TmhzHwhnj
SV64nTApS0gBsc6c18fUBsMcUj5nCNclIzfxwnARd/30yg22r09nUY2gtQTwk/W6VCpAH+7yZkH1
TLNGa+UmMnPsnBjlAJ6l9VPsa4uJM2DIQKtZXWq4DkhSAYKF6joIP7nKMDswHzAHBgUrDgMCGgQU
wTM1Z+CJZG9xAcf1zAVGl4ggYyYEFGBFyJ8VBwijS2zy1qwN1WYGtcWoAgIH0A==
";
public static X509Certificate2 GetX509Certificate2()
{
byte[] data = Convert.FromBase64String(Data);
return new X509Certificate2(data);
}
}
}

View File

@@ -0,0 +1,47 @@
using JetBrains.Annotations;
namespace WireMock.Logging
{
/// <summary>
/// IWireMockLogger interface
/// </summary>
[PublicAPI]
public interface IWireMockLogger
{
/// <summary>
/// Writes the message at the Debug level using the specified parameters.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI]
[StringFormatMethod("formatString")]
void Debug([NotNull] string formatString, [NotNull] params object[] args);
/// <summary>
/// Writes the message at the Info level using the specified parameters.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI]
[StringFormatMethod("formatString")]
void Info([NotNull] string formatString, [NotNull] params object[] args);
/// <summary>
/// Writes the message at the Warning level using the specified parameters.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI]
[StringFormatMethod("formatString")]
void Warn([NotNull] string formatString, [NotNull] params object[] args);
/// <summary>
/// Writes the message at the Error level using the specified parameters.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI]
[StringFormatMethod("formatString")]
void Error([NotNull] string formatString, [NotNull] params object[] args);
}
}

View File

@@ -0,0 +1,42 @@
using System;
namespace WireMock.Logging
{
/// <summary>
/// WireMockConsoleLogger which logs to Console
/// </summary>
/// <seealso cref="IWireMockLogger" />
public class WireMockConsoleLogger : IWireMockLogger
{
/// <see cref="IWireMockLogger.Debug"/>
public void Debug(string formatString, params object[] args)
{
Console.WriteLine(Format("Debug", formatString, args));
}
/// <see cref="IWireMockLogger.Info"/>
public void Info(string formatString, params object[] args)
{
Console.WriteLine(Format("Info", formatString, args));
}
/// <see cref="IWireMockLogger.Warn"/>
public void Warn(string formatString, params object[] args)
{
Console.WriteLine(Format("Warn", formatString, args));
}
/// <see cref="IWireMockLogger.Error"/>
public void Error(string formatString, params object[] args)
{
Console.WriteLine(Format("Error", formatString, args));
}
private static string Format(string level, string formatString, params object[] args)
{
string message = string.Format(formatString, args);
return $"{DateTime.UtcNow} [{level}] : {message}";
}
}
}

View File

@@ -0,0 +1,29 @@
namespace WireMock.Logging
{
/// <summary>
/// WireMockNullLogger which does not log.
/// </summary>
/// <seealso cref="IWireMockLogger" />
public class WireMockNullLogger : IWireMockLogger
{
/// <see cref="IWireMockLogger.Debug"/>
public void Debug(string formatString, params object[] args)
{
}
/// <see cref="IWireMockLogger.Info"/>
public void Info(string formatString, params object[] args)
{
}
/// <see cref="IWireMockLogger.Warn"/>
public void Warn(string formatString, params object[] args)
{
}
/// <see cref="IWireMockLogger.Error"/>
public void Error(string formatString, params object[] args)
{
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using WireMock.ResponseProviders;
namespace WireMock namespace WireMock
{ {
@@ -13,25 +14,21 @@ namespace WireMock
/// <summary> /// <summary>
/// Gets the unique identifier. /// Gets the unique identifier.
/// </summary> /// </summary>
/// <value>
/// The unique identifier.
/// </value>
public Guid Guid { get; } public Guid Guid { get; }
/// <summary> /// <summary>
/// Gets the unique title. /// Gets the unique title.
/// </summary> /// </summary>
/// <value>
/// The unique title.
/// </value>
public string Title { get; } public string Title { get; }
/// <summary>
/// The full filename path for this mapping (only defined for static mappings).
/// </summary>
public string Path { get; set; }
/// <summary> /// <summary>
/// Gets the priority. /// Gets the priority.
/// </summary> /// </summary>
/// <value>
/// The priority.
/// </value>
public int Priority { get; } public int Priority { get; }
/// <summary> /// <summary>
@@ -72,17 +69,19 @@ namespace WireMock
/// Initializes a new instance of the <see cref="Mapping"/> class. /// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary> /// </summary>
/// <param name="guid">The unique identifier.</param> /// <param name="guid">The unique identifier.</param>
/// <param name="title">The unique title (can be null_.</param> /// <param name="title">The unique title (can be null).</param>
/// <param name="path">The full file path from this mapping title (can be null).</param>
/// <param name="requestMatcher">The request matcher.</param> /// <param name="requestMatcher">The request matcher.</param>
/// <param name="provider">The provider.</param> /// <param name="provider">The provider.</param>
/// <param name="priority">The priority for this mapping.</param> /// <param name="priority">The priority for this mapping.</param>
/// <param name="scenario">The scenario. [Optional]</param> /// <param name="scenario">The scenario. [Optional]</param>
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param> /// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param> /// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
public Mapping(Guid guid, [CanBeNull] string title, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, [CanBeNull] string scenario, [CanBeNull] object executionConditionState, [CanBeNull] object nextState) public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path, IRequestMatcher requestMatcher, IResponseProvider provider, int priority, [CanBeNull] string scenario, [CanBeNull] object executionConditionState, [CanBeNull] object nextState)
{ {
Guid = guid; Guid = guid;
Title = title; Title = title;
Path = path;
RequestMatcher = requestMatcher; RequestMatcher = requestMatcher;
Provider = provider; Provider = provider;
Priority = priority; Priority = priority;

View File

@@ -7,8 +7,8 @@ namespace WireMock.Matchers
/// <summary> /// <summary>
/// ExactMatcher /// ExactMatcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="IStringMatcher" />
public class ExactMatcher : IMatcher public class ExactMatcher : IStringMatcher
{ {
private readonly string[] _values; private readonly string[] _values;
@@ -23,29 +23,19 @@ namespace WireMock.Matchers
_values = values; _values = values;
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.IsMatch"/>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(string input) public double IsMatch(string input)
{ {
return MatchScores.ToScore(_values.Select(value => value.Equals(input))); return MatchScores.ToScore(_values.Select(value => value.Equals(input)));
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// Gets the value.
/// </summary>
/// <returns>Patterns</returns>
public string[] GetPatterns() public string[] GetPatterns()
{ {
return _values; return _values;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
public string GetName() public string GetName()
{ {
return "ExactMatcher"; return "ExactMatcher";

View File

@@ -0,0 +1,46 @@
using System.Linq;
using JetBrains.Annotations;
namespace WireMock.Matchers
{
/// <summary>
/// ExactMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
{
private readonly object _object;
private readonly byte[] _bytes;
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value)
{
_object = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value)
{
_bytes = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool equals = _object != null ? Equals(_object, input) : _bytes.SequenceEqual((byte[])input);
return MatchScores.ToScore(equals);
}
/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "ExactObjectMatcher";
}
}
}

View File

@@ -5,19 +5,6 @@
/// </summary> /// </summary>
public interface IMatcher public interface IMatcher
{ {
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
string[] GetPatterns();
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
/// </summary> /// </summary>

View File

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

View File

@@ -0,0 +1,21 @@
namespace WireMock.Matchers
{
/// <summary>
/// IStringMatcher
/// </summary>
public interface IStringMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(string input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
string[] GetPatterns();
}
}

View File

@@ -10,8 +10,9 @@ namespace WireMock.Matchers
/// JSONPathMatcher /// JSONPathMatcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="IMatcher" />
public class JsonPathMatcher : IMatcher public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{ {
// private readonly object _jsonPattern;
private readonly string[] _patterns; private readonly string[] _patterns;
/// <summary> /// <summary>
@@ -25,15 +26,20 @@ namespace WireMock.Matchers
_patterns = patterns; _patterns = patterns;
} }
/// <summary> //public JsonPathMatcher([NotNull] object jsonPattern)
/// Determines whether the specified input is match. //{
/// </summary> // Check.NotNull(jsonPattern, nameof(jsonPattern));
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns> // _jsonPattern = jsonPattern;
//}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input) public double IsMatch(string input)
{ {
if (input == null) if (input == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
try try
{ {
@@ -47,19 +53,33 @@ namespace WireMock.Matchers
} }
} }
/// <summary> /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
/// Gets the patterns. public double IsMatch(object input)
/// </summary> {
/// <returns>Pattern</returns> if (input == null)
{
return MatchScores.Mismatch;
}
try
{
var o = input as JObject ?? JObject.FromObject(input);
return MatchScores.ToScore(_patterns.Select(p => o.SelectToken(p) != null));
}
catch (Exception)
{
return MatchScores.Mismatch;
}
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns() public string[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
public string GetName() public string GetName()
{ {
return "JsonPathMatcher"; return "JsonPathMatcher";

View File

@@ -9,8 +9,8 @@ namespace WireMock.Matchers
/// <summary> /// <summary>
/// Regular Expression Matcher /// Regular Expression Matcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="IStringMatcher" />
public class RegexMatcher : IMatcher public class RegexMatcher : IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
private readonly Regex[] _expressions; private readonly Regex[] _expressions;
@@ -37,20 +37,20 @@ namespace WireMock.Matchers
RegexOptions options = RegexOptions.Compiled; RegexOptions options = RegexOptions.Compiled;
if (ignoreCase) if (ignoreCase)
{
options |= RegexOptions.IgnoreCase; options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => new Regex(p, options)).ToArray(); _expressions = patterns.Select(p => new Regex(p, options)).ToArray();
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.IsMatch"/>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(string input) public double IsMatch(string input)
{ {
if (input == null) if (input == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
try try
{ {
@@ -62,21 +62,13 @@ namespace WireMock.Matchers
} }
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// Gets the patterns.
/// </summary>
/// <returns>Pattern</returns>
public virtual string[] GetPatterns() public virtual string[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>
/// Name
/// </returns>
public virtual string GetName() public virtual string GetName()
{ {
return "RegexMatcher"; return "RegexMatcher";

View File

@@ -9,21 +9,21 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
public class RequestMessageBodyMatcher : IRequestMatcher public class RequestMessageBodyMatcher : IRequestMatcher
{ {
/// <summary>
/// The body as byte[].
/// </summary>
private readonly byte[] _bodyData;
/// <summary> /// <summary>
/// The body function /// The body function
/// </summary> /// </summary>
public Func<string, bool> Func { get; } public Func<string, bool> Func { get; }
/// <summary> /// <summary>
/// The body data function /// The body data function for byte[]
/// </summary> /// </summary>
public Func<byte[], bool> DataFunc { get; } public Func<byte[], bool> DataFunc { get; }
/// <summary>
/// The body data function for json
/// </summary>
public Func<object, bool> JsonFunc { get; }
/// <summary> /// <summary>
/// The matcher. /// The matcher.
/// </summary> /// </summary>
@@ -32,9 +32,7 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
/// <param name="body"> /// <param name="body">The body.</param>
/// The body Regex pattern.
/// </param>
public RequestMessageBodyMatcher([NotNull] string body) : this(new SimMetricsMatcher(body)) public RequestMessageBodyMatcher([NotNull] string body) : this(new SimMetricsMatcher(body))
{ {
} }
@@ -42,21 +40,23 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
/// <param name="body"> /// <param name="body">The body.</param>
/// The body Regex pattern. public RequestMessageBodyMatcher([NotNull] byte[] body) : this(new ExactObjectMatcher(body))
/// </param>
public RequestMessageBodyMatcher([NotNull] byte[] body)
{ {
Check.NotNull(body, nameof(body));
_bodyData = body;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="body">The body.</param>
/// The body func. public RequestMessageBodyMatcher([NotNull] object body) : this(new ExactObjectMatcher(body))
/// </param> {
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func) public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(func, nameof(func));
@@ -66,9 +66,7 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="func">The function.</param>
/// The body func.
/// </param>
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func) public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(func, nameof(func));
@@ -78,23 +76,24 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matcher"> /// <param name="func">The function.</param>
/// The body matcher. public RequestMessageBodyMatcher([NotNull] Func<object, bool> func)
/// </param> {
Check.NotNull(func, nameof(func));
JsonFunc = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matcher">The matcher.</param>
public RequestMessageBodyMatcher([NotNull] IMatcher matcher) public RequestMessageBodyMatcher([NotNull] IMatcher matcher)
{ {
Check.NotNull(matcher, nameof(matcher)); Check.NotNull(matcher, nameof(matcher));
Matcher = matcher; Matcher = matcher;
} }
/// <summary> /// <see cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -103,17 +102,43 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (Matcher != null) if (requestMessage.Body != null)
return Matcher.IsMatch(requestMessage.Body); {
var stringMatcher = Matcher as IStringMatcher;
if (stringMatcher != null)
{
return stringMatcher.IsMatch(requestMessage.Body);
}
}
if (_bodyData != null) var objectMatcher = Matcher as IObjectMatcher;
return MatchScores.ToScore(requestMessage.BodyAsBytes == _bodyData); if (objectMatcher != null)
{
if (requestMessage.BodyAsJson != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
}
if (requestMessage.BodyAsBytes != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}
if (Func != null) if (Func != null)
{
return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body)); return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body));
}
if (DataFunc != null && requestMessage.BodyAsBytes != null) if (DataFunc != null)
{
return MatchScores.ToScore(requestMessage.BodyAsBytes != null && DataFunc(requestMessage.BodyAsBytes)); return MatchScores.ToScore(requestMessage.BodyAsBytes != null && DataFunc(requestMessage.BodyAsBytes));
}
if (JsonFunc != null)
{
return MatchScores.ToScore(requestMessage.BodyAsJson != null && JsonFunc(requestMessage.BodyAsJson));
}
return MatchScores.Mismatch; return MatchScores.Mismatch;
} }

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The matchers. /// The matchers.
/// </summary> /// </summary>
public IReadOnlyList<IMatcher> Matchers { get; } public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary> /// <summary>
/// The ClientIP functions. /// The ClientIP functions.
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary> /// </summary>
/// <param name="clientIPs">The clientIPs.</param> /// <param name="clientIPs">The clientIPs.</param>
public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).ToArray()) public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast<IStringMatcher>().ToArray())
{ {
} }
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
public RequestMessageClientIPMatcher([NotNull] params IMatcher[] matchers) public RequestMessageClientIPMatcher([NotNull] params IStringMatcher[] matchers)
{ {
Check.NotNull(matchers, nameof(matchers)); Check.NotNull(matchers, nameof(matchers));
Matchers = matchers; Matchers = matchers;
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -66,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.ClientIP)); return Matchers.Max(matcher => matcher.IsMatch(requestMessage.ClientIP));
}
if (Funcs != null) if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.ClientIP != null && Funcs.Any(func => func(requestMessage.ClientIP))); return MatchScores.ToScore(requestMessage.ClientIP != null && Funcs.Any(func => func(requestMessage.ClientIP)));
}
return MatchScores.Mismatch; return MatchScores.Mismatch;
} }

View File

@@ -24,7 +24,7 @@ namespace WireMock.Matchers.Request
/// <value> /// <value>
/// The matchers. /// The matchers.
/// </value> /// </value>
public IMatcher[] Matchers { get; } public IStringMatcher[] Matchers { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
@@ -38,7 +38,7 @@ namespace WireMock.Matchers.Request
Check.NotNull(pattern, nameof(pattern)); Check.NotNull(pattern, nameof(pattern));
Name = name; Name = name;
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
} }
/// <summary> /// <summary>
@@ -46,7 +46,7 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(matchers, nameof(matchers)); Check.NotNull(matchers, nameof(matchers));
@@ -83,16 +83,24 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (requestMessage.Cookies == null) if (requestMessage.Cookies == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
if (Funcs != null) if (Funcs != null)
{
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Cookies))); return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Cookies)));
}
if (Matchers == null) if (Matchers == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
if (!requestMessage.Cookies.ContainsKey(Name)) if (!requestMessage.Cookies.ContainsKey(Name))
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
string value = requestMessage.Cookies[Name]; string value = requestMessage.Cookies[Name];
return Matchers.Max(m => m.IsMatch(value)); return Matchers.Max(m => m.IsMatch(value));

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request
@@ -9,12 +10,13 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The request header matcher. /// The request header matcher.
/// </summary> /// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageHeaderMatcher : IRequestMatcher public class RequestMessageHeaderMatcher : IRequestMatcher
{ {
/// <summary> /// <summary>
/// The functions /// The functions
/// </summary> /// </summary>
public Func<IDictionary<string, string>, bool>[] Funcs { get; } public Func<IDictionary<string, string[]>, bool>[] Funcs { get; }
/// <summary> /// <summary>
/// The name /// The name
@@ -24,21 +26,36 @@ namespace WireMock.Matchers.Request
/// <value> /// <value>
/// The matchers. /// The matchers.
/// </value> /// </value>
public IMatcher[] Matchers { get; } public IStringMatcher[] Matchers { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">The ignoreCase.</param> /// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true) public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(pattern, nameof(pattern)); Check.NotNull(pattern, nameof(pattern));
Name = name; Name = name;
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string[] patterns, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(patterns, nameof(patterns));
Name = name;
Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast<IStringMatcher>().ToArray();
} }
/// <summary> /// <summary>
@@ -46,7 +63,7 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(matchers, nameof(matchers)); Check.NotNull(matchers, nameof(matchers));
@@ -59,21 +76,14 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary> /// </summary>
/// <param name="funcs">The funcs.</param> /// <param name="funcs">The funcs.</param>
public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs) public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string[]>, bool>[] funcs)
{ {
Check.NotNull(funcs, nameof(funcs)); Check.NotNull(funcs, nameof(funcs));
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -83,19 +93,27 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (requestMessage.Headers == null) if (requestMessage.Headers == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
if (Funcs != null) if (Funcs != null)
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers))); {
return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray()))));
}
if (Matchers == null) if (Matchers == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
if (!requestMessage.Headers.ContainsKey(Name)) if (!requestMessage.Headers.ContainsKey(Name))
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
string value = requestMessage.Headers[Name]; WireMockList<string> list = requestMessage.Headers[Name];
return Matchers.Max(m => m.IsMatch(value)); return Matchers.Max(m => list.Max(value => m.IsMatch(value))); // TODO : is this correct ?
} }
} }
} }

View File

@@ -30,12 +30,8 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary> /// </summary>
/// <param name="key"> /// <param name="key">The key.</param>
/// The key. /// <param name="values">The values.</param>
/// </param>
/// <param name="values">
/// The values.
/// </param>
public RequestMessageParamMatcher([NotNull] string key, [CanBeNull] IEnumerable<string> values) public RequestMessageParamMatcher([NotNull] string key, [CanBeNull] IEnumerable<string> values)
{ {
Check.NotNull(key, nameof(key)); Check.NotNull(key, nameof(key));
@@ -51,17 +47,11 @@ namespace WireMock.Matchers.Request
public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs) public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{ {
Check.NotNull(funcs, nameof(funcs)); Check.NotNull(funcs, nameof(funcs));
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -71,7 +61,9 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (Funcs != null) if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query))); return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
List<string> values = requestMessage.GetParameter(Key); List<string> values = requestMessage.GetParameter(Key);

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The matcher. /// The matcher.
/// </summary> /// </summary>
public IReadOnlyList<IMatcher> Matchers { get; } public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary> /// <summary>
/// The path functions /// The path functions
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="paths">The paths.</param> /// <param name="paths">The paths.</param>
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).ToArray()) public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast<IStringMatcher>().ToArray())
{ {
} }
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers) public RequestMessagePathMatcher([NotNull] params IStringMatcher[] matchers)
{ {
Check.NotNull(matchers, nameof(matchers)); Check.NotNull(matchers, nameof(matchers));
Matchers = matchers; Matchers = matchers;
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -66,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{
return Matchers.Max(m => m.IsMatch(requestMessage.Path)); return Matchers.Max(m => m.IsMatch(requestMessage.Path));
}
if (Funcs != null) if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Path != null && Funcs.Any(func => func(requestMessage.Path))); return MatchScores.ToScore(requestMessage.Path != null && Funcs.Any(func => func(requestMessage.Path)));
}
return MatchScores.Mismatch; return MatchScores.Mismatch;
} }

View File

@@ -14,7 +14,7 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The matchers. /// The matchers.
/// </summary> /// </summary>
public IReadOnlyList<IMatcher> Matchers { get; } public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <summary> /// <summary>
/// The url functions. /// The url functions.
@@ -25,7 +25,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="urls">The urls.</param> /// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).ToArray()) public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast<IStringMatcher>().ToArray())
{ {
} }
@@ -33,7 +33,7 @@ namespace WireMock.Matchers.Request
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers) public RequestMessageUrlMatcher([NotNull] params IStringMatcher[] matchers)
{ {
Check.NotNull(matchers, nameof(matchers)); Check.NotNull(matchers, nameof(matchers));
Matchers = matchers; Matchers = matchers;
@@ -49,14 +49,7 @@ namespace WireMock.Matchers.Request
Funcs = funcs; Funcs = funcs;
} }
/// <summary> /// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
/// Determines whether the specified RequestMessage is match.
/// </summary>
/// <param name="requestMessage">The RequestMessage.</param>
/// <param name="requestMatchResult">The RequestMatchResult.</param>
/// <returns>
/// A value between 0.0 - 1.0 of the similarity.
/// </returns>
public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); double score = IsMatch(requestMessage);
@@ -66,10 +59,14 @@ namespace WireMock.Matchers.Request
private double IsMatch(RequestMessage requestMessage) private double IsMatch(RequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.Url)); return Matchers.Max(matcher => matcher.IsMatch(requestMessage.Url));
}
if (Funcs != null) if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Url != null && Funcs.Any(func => func(requestMessage.Url))); return MatchScores.ToScore(requestMessage.Url != null && Funcs.Any(func => func(requestMessage.Url)));
}
return MatchScores.Mismatch; return MatchScores.Mismatch;
} }

View File

@@ -10,8 +10,8 @@ namespace WireMock.Matchers
/// <summary> /// <summary>
/// SimMetricsMatcher /// SimMetricsMatcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="IStringMatcher" />
public class SimMetricsMatcher : IMatcher public class SimMetricsMatcher : IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
private readonly SimMetricType _simMetricType; private readonly SimMetricType _simMetricType;
@@ -32,17 +32,13 @@ namespace WireMock.Matchers
/// <param name="simMetricType">The SimMetric Type</param> /// <param name="simMetricType">The SimMetric Type</param>
public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein)
{ {
Check.NotEmpty(patterns, nameof(patterns)); Check.NotNullOrEmpty(patterns, nameof(patterns));
_patterns = patterns; _patterns = patterns;
_simMetricType = simMetricType; _simMetricType = simMetricType;
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.IsMatch"/>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(string input) public double IsMatch(string input)
{ {
IStringMetric m = GetStringMetricType(); IStringMetric m = GetStringMetricType();
@@ -93,19 +89,13 @@ namespace WireMock.Matchers
} }
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public string[] GetPatterns() public string[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
public string GetName() public string GetName()
{ {
return $"SimMetricsMatcher.{_simMetricType}"; return $"SimMetricsMatcher.{_simMetricType}";

View File

@@ -7,7 +7,7 @@ namespace WireMock.Matchers
/// <summary> /// <summary>
/// WildcardMatcher /// WildcardMatcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="RegexMatcher" />
public class WildcardMatcher : RegexMatcher public class WildcardMatcher : RegexMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
@@ -31,21 +31,13 @@ namespace WireMock.Matchers
_patterns = patterns; _patterns = patterns;
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public override string[] GetPatterns() public override string[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>
/// Name
/// </returns>
public override string GetName() public override string GetName()
{ {
return "WildcardMatcher"; return "WildcardMatcher";

View File

@@ -12,8 +12,8 @@ namespace WireMock.Matchers
/// <summary> /// <summary>
/// XPath2Matcher /// XPath2Matcher
/// </summary> /// </summary>
/// <seealso cref="WireMock.Matchers.IMatcher" /> /// <seealso cref="IStringMatcher" />
public class XPathMatcher : IMatcher public class XPathMatcher : IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
@@ -28,15 +28,13 @@ namespace WireMock.Matchers
_patterns = patterns; _patterns = patterns;
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.IsMatch"/>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input string</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(string input) public double IsMatch(string input)
{ {
if (input == null) if (input == null)
{
return MatchScores.Mismatch; return MatchScores.Mismatch;
}
try try
{ {
@@ -53,19 +51,13 @@ namespace WireMock.Matchers
} }
} }
/// <summary> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
public string[] GetPatterns() public string[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <summary> /// <inheritdoc cref="IMatcher.GetName"/>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
public string GetName() public string GetName()
{ {
return "XPathMatcher"; return "XPathMatcher";

View File

@@ -1,11 +1,14 @@
#if NETSTANDARD #if NETSTANDARD
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using WireMock.Http; using WireMock.Http;
using WireMock.HttpsCertificate;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Owin namespace WireMock.Owin
@@ -14,7 +17,7 @@ namespace WireMock.Owin
{ {
private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly WireMockMiddlewareOptions _options; private readonly WireMockMiddlewareOptions _options;
private readonly string[] _uriPrefixes; private readonly string[] _urls;
private IWebHost _host; private IWebHost _host;
@@ -27,7 +30,7 @@ namespace WireMock.Owin
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes) public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{ {
Check.NotNull(options, nameof(options)); Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes)); Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes) foreach (string uriPrefix in uriPrefixes)
{ {
@@ -38,7 +41,7 @@ namespace WireMock.Owin
} }
_options = options; _options = options;
_uriPrefixes = uriPrefixes; _urls = uriPrefixes;
} }
public Task StartAsync() public Task StartAsync()
@@ -46,23 +49,59 @@ namespace WireMock.Owin
_host = new WebHostBuilder() _host = new WebHostBuilder()
.Configure(appBuilder => .Configure(appBuilder =>
{ {
appBuilder.UseMiddleware<GlobalExceptionMiddleware>(_options);
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>(_options); appBuilder.UseMiddleware<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
}) })
.UseKestrel() .UseKestrel(options =>
.UseUrls(_uriPrefixes) {
#if NETSTANDARD1_3
if (_urls.Any(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
{
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
}
#else
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x
foreach (string url in _urls.Where(u => u.StartsWith("http://", StringComparison.OrdinalIgnoreCase)))
{
PortUtil.TryExtractProtocolAndPort(url, out string host, out int port);
options.Listen(System.Net.IPAddress.Loopback, port);
}
foreach (string url in _urls.Where(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
{
PortUtil.TryExtractProtocolAndPort(url, out string host, out int port);
options.Listen(System.Net.IPAddress.Loopback, port, listenOptions =>
{
listenOptions.UseHttps(PublicCertificateHelper.GetX509Certificate2());
});
}
#endif
})
#if NETSTANDARD1_3
.UseUrls(_urls)
#endif
.Build(); .Build();
IsStarted = true;
#if NETSTANDARD1_3 #if NETSTANDARD1_3
System.Console.WriteLine("WireMock.Net server using netstandard1.3"); Console.WriteLine("WireMock.Net server using netstandard1.3");
return Task.Run(() => return Task.Run(() =>
{ {
_host.Run(_cts.Token); _host.Run(_cts.Token);
IsStarted = true;
}, _cts.Token); }, _cts.Token);
#else #else
System.Console.WriteLine("WireMock.Net server using netstandard2.0"); System.Console.WriteLine("WireMock.Net server using netstandard2.0");
IsStarted = true;
return _host.RunAsync(_cts.Token); return Task.Run(() =>
{
_host.Run();
}, _cts.Token);
#endif #endif
} }

View File

@@ -0,0 +1,56 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
#if !NETSTANDARD
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
#if !NETSTANDARD
internal class GlobalExceptionMiddleware : OwinMiddleware
#else
internal class GlobalExceptionMiddleware
#endif
{
private readonly WireMockMiddlewareOptions _options;
#if !NETSTANDARD
public GlobalExceptionMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
{
_options = options;
}
#else
public GlobalExceptionMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
{
Next = next;
_options = options;
}
#endif
#if NETSTANDARD
public RequestDelegate Next { get; }
#endif
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
#if !NETSTANDARD
public override async Task Invoke(IOwinContext ctx)
#else
public async Task Invoke(HttpContext ctx)
#endif
{
try
{
await Next?.Invoke(ctx);
}
catch (Exception ex)
{
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
await _responseMapper.MapAsync(new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) }, ctx.Response);
}
}
}
}

View File

@@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; // using System.IO;
using System.Linq; using System.Linq;
using System.Text; // using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using WireMock.Util;
#if !NETSTANDARD #if !NETSTANDARD
using Microsoft.Owin; using Microsoft.Owin;
#else #else
@@ -16,7 +17,7 @@ namespace WireMock.Owin
/// <summary> /// <summary>
/// OwinRequestMapper /// OwinRequestMapper
/// </summary> /// </summary>
public class OwinRequestMapper internal class OwinRequestMapper
{ {
/// <summary> /// <summary>
/// MapAsync IOwinRequest to RequestMessage /// MapAsync IOwinRequest to RequestMessage
@@ -43,32 +44,49 @@ namespace WireMock.Owin
#endif #endif
string method = request.Method; string method = request.Method;
string bodyAsString = null; Dictionary<string, string[]> headers = null;
byte[] body = null; if (request.Headers.Any())
Encoding bodyEncoding = null;
if (request.Body != null)
{ {
using (var streamReader = new StreamReader(request.Body)) headers = new Dictionary<string, string[]>();
foreach (var header in request.Headers)
{ {
bodyAsString = await streamReader.ReadToEndAsync(); headers.Add(header.Key, header.Value);
bodyEncoding = streamReader.CurrentEncoding;
} }
body = bodyEncoding.GetBytes(bodyAsString);
} }
var listenerHeaders = request.Headers; IDictionary<string, string> cookies = null;
if (request.Cookies.Any())
{
cookies = new Dictionary<string, string>();
foreach (var cookie in request.Cookies)
{
cookies.Add(cookie.Key, cookie.Value);
}
}
var headers = new Dictionary<string, string>(); BodyData body = null;
foreach (var header in listenerHeaders) if (request.Body != null && ShouldParseBody(method))
headers.Add(header.Key, header.Value.FirstOrDefault()); {
body = await BodyParser.Parse(request.Body, request.ContentType);
}
var cookies = new Dictionary<string, string>(); return new RequestMessage(url, method, clientIP, body, headers, cookies) { DateTime = DateTime.Now };
}
foreach (var cookie in request.Cookies) private bool ShouldParseBody(string method)
cookies.Add(cookie.Key, cookie.Value); {
/*
return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now }; HEAD - No defined body semantics.
GET - No defined body semantics.
PUT - Body supported.
POST - Body supported.
DELETE - No defined body semantics.
TRACE - Body not supported.
OPTIONS - Body supported but no semantics on usage (maybe in the future).
CONNECT - No defined body semantics
PATCH - Body supported.
*/
return new[] { "PUT", "POST", "OPTIONS", "PATCH" }.Contains(method.ToUpper());
} }
} }
} }

View File

@@ -1,7 +1,11 @@
using System.IO; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json;
using WireMock.Util;
#if !NETSTANDARD #if !NETSTANDARD
using Microsoft.Owin; using Microsoft.Owin;
#else #else
@@ -17,6 +21,19 @@ namespace WireMock.Owin
{ {
private readonly Encoding _utf8NoBom = new UTF8Encoding(false); private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
// https://stackoverflow.com/questions/239725/cannot-set-some-http-headers-when-using-system-net-webrequest
#if !NETSTANDARD
private static readonly IDictionary<string, Action<IOwinResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<IOwinResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#else
private static readonly IDictionary<string, Action<HttpResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<HttpResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#endif
{ "Content-Length", null },
{ "Content-Type", (r, v) => r.ContentType = v.FirstOrDefault() },
{ "Keep-Alive", null },
{ "Transfer-Encoding", null },
{ "WWW-Authenticate", null }
};
/// <summary> /// <summary>
/// MapAsync ResponseMessage to OwinResponse /// MapAsync ResponseMessage to OwinResponse
/// </summary> /// </summary>
@@ -32,13 +49,54 @@ namespace WireMock.Owin
{ {
response.StatusCode = responseMessage.StatusCode; response.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value)); // Set headers
foreach (var pair in responseMessage.Headers)
{
if (RestrictedResponseHeaders.ContainsKey(pair.Key))
{
RestrictedResponseHeaders[pair.Key]?.Invoke(response, pair.Value);
}
else
{
#if !NETSTANDARD
response.Headers.AppendValues(pair.Key, pair.Value.ToArray());
#else
response.Headers.Append(pair.Key, pair.Value.ToArray());
#endif
}
}
if (responseMessage.Body == null) if (responseMessage.Body == null && responseMessage.BodyAsBytes == null && responseMessage.BodyAsFile == null && responseMessage.BodyAsJson == null)
{
return; return;
}
Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom; if (responseMessage.BodyAsBytes != null)
using (var writer = new StreamWriter(response.Body, encoding)) {
await response.Body.WriteAsync(responseMessage.BodyAsBytes, 0, responseMessage.BodyAsBytes.Length);
return;
}
if (responseMessage.BodyAsFile != null)
{
byte[] bytes = File.ReadAllBytes(responseMessage.BodyAsFile);
await response.Body.WriteAsync(bytes, 0, bytes.Length);
return;
}
if (responseMessage.BodyAsJson != null)
{
string jsonBody = JsonConvert.SerializeObject(responseMessage.BodyAsJson, new JsonSerializerSettings { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore });
using (var writer = new StreamWriter(response.Body, responseMessage.BodyEncoding ?? _utf8NoBom))
{
await writer.WriteAsync(jsonBody);
}
return;
}
using (var writer = new StreamWriter(response.Body, responseMessage.BodyEncoding ?? _utf8NoBom))
{ {
await writer.WriteAsync(responseMessage.Body); await writer.WriteAsync(responseMessage.Body);
} }

View File

@@ -19,7 +19,7 @@ namespace WireMock.Owin
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes) public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{ {
Check.NotNull(options, nameof(options)); Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes)); Check.NotNullOrEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes) foreach (string uriPrefix in uriPrefixes)
{ {
@@ -57,11 +57,14 @@ namespace WireMock.Owin
private void StartServers() private void StartServers()
{ {
System.Console.WriteLine("WireMock.Net server using .net 4.5.x or .net 4.6.x"); Console.WriteLine("WireMock.Net server using .net 4.5.x or higher");
Action<IAppBuilder> startup = app => Action<IAppBuilder> startup = app =>
{ {
app.Use<GlobalExceptionMiddleware>(_options);
_options.PreWireMockMiddlewareInit?.Invoke(app);
app.Use<WireMockMiddleware>(_options); app.Use<WireMockMiddleware>(_options);
_options.PostWireMockMiddlewareInit?.Invoke(app);
}; };
var servers = new List<IDisposable>(); var servers = new List<IDisposable>();

View File

@@ -4,6 +4,9 @@ using WireMock.Logging;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
using System.Linq; using System.Linq;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
using WireMock.Http;
#if !NETSTANDARD #if !NETSTANDARD
using Microsoft.Owin; using Microsoft.Owin;
#else #else
@@ -50,7 +53,7 @@ namespace WireMock.Owin
RequestMatchResult requestMatchResult = null; RequestMatchResult requestMatchResult = null;
try try
{ {
foreach (var mapping in _options.Mappings.Where(m => m.Scenario != null)) foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null))
{ {
// Set start // Set start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState) if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
@@ -59,7 +62,7 @@ namespace WireMock.Owin
} }
} }
var mappings = _options.Mappings var mappings = _options.Mappings.Values
.Select(m => new .Select(m => new
{ {
Mapping = m, Mapping = m,
@@ -93,6 +96,7 @@ namespace WireMock.Owin
if (targetMapping == null) if (targetMapping == null)
{ {
logRequest = true; logRequest = true;
_options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" }; response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return; return;
} }
@@ -101,9 +105,10 @@ namespace WireMock.Owin
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null) if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{ {
bool present = request.Headers.TryGetValue("Authorization", out string authorization); bool present = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out WireMockList<string> authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < MatchScores.Perfect) if (!present || _options.AuthorizationMatcher.IsMatch(authorization.ToString()) < MatchScores.Perfect)
{ {
_options.Logger.Error("HttpStatusCode set to 401");
response = new ResponseMessage { StatusCode = 401 }; response = new ResponseMessage { StatusCode = 401 };
return; return;
} }
@@ -123,7 +128,8 @@ namespace WireMock.Owin
} }
catch (Exception ex) catch (Exception ex)
{ {
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() }; _options.Logger.Error("HttpStatusCode set to 500");
response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
} }
finally finally
{ {

View File

@@ -4,25 +4,43 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Util;
#if !NETSTANDARD
using Owin;
#else
using Microsoft.AspNetCore.Builder;
#endif
namespace WireMock.Owin namespace WireMock.Owin
{ {
internal class WireMockMiddlewareOptions internal class WireMockMiddlewareOptions
{ {
public IWireMockLogger Logger { get; set; }
public TimeSpan? RequestProcessingDelay { get; set; } public TimeSpan? RequestProcessingDelay { get; set; }
public IMatcher AuthorizationMatcher { get; set; } public IStringMatcher AuthorizationMatcher { get; set; }
public bool AllowPartialMapping { get; set; } public bool AllowPartialMapping { get; set; }
public IList<Mapping> Mappings { get; set; } = new List<Mapping>(); public IDictionary<Guid, Mapping> Mappings { get; } = new ConcurrentDictionary<Guid, Mapping>();
public ObservableCollection<LogEntry> LogEntries { get; } = new ObservableCollection<LogEntry>(); public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();
public int? RequestLogExpirationDuration { get; set; } public int? RequestLogExpirationDuration { get; set; }
public int? MaxRequestLogCount { get; set; } public int? MaxRequestLogCount { get; set; }
public IDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>(); public IDictionary<string, object> Scenarios { get; } = new ConcurrentDictionary<string, object>();
#if !NETSTANDARD
public Action<IAppBuilder> PreWireMockMiddlewareInit { get; set; }
public Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
#else
public Action<IApplicationBuilder> PreWireMockMiddlewareInit { get; set; }
public Action<IApplicationBuilder> PostWireMockMiddlewareInit { get; set; }
#endif
} }
} }

View File

@@ -10,38 +10,52 @@ namespace WireMock.RequestBuilders
public interface IBodyRequestBuilder public interface IBodyRequestBuilder
{ {
/// <summary> /// <summary>
/// The with body. /// WithBody: IMatcher
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] IMatcher matcher); IRequestBuilder WithBody([NotNull] IMatcher matcher);
/// <summary> /// <summary>
/// The with body. /// WithBody: Body as string
/// </summary> /// </summary>
/// <param name="body">The body.</param> /// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody(string body); IRequestBuilder WithBody(string body);
/// <summary> /// <summary>
/// The with body byte[]. /// WithBody: Body as byte[]
/// </summary> /// </summary>
/// <param name="body">The body as byte[].</param> /// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody(byte[] body); IRequestBuilder WithBody(byte[] body);
/// <summary> /// <summary>
/// The with body string func. /// WithBody: Body as object
/// </summary> /// </summary>
/// <param name="body">The body string function.</param> /// <param name="body">The body.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<string, bool> body); IRequestBuilder WithBody(object body);
/// <summary> /// <summary>
/// The with body byte[] func. ///WithBody: func (string)
/// </summary> /// </summary>
/// <param name="body">The body byte[] function.</param> /// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<byte[], bool> body); IRequestBuilder WithBody([NotNull] Func<string, bool> func);
/// <summary>
///WithBody: func (byte[])
/// </summary>
/// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<byte[], bool> func);
/// <summary>
///WithBody: func (object)
/// </summary>
/// <param name="func">The function.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody([NotNull] Func<object, bool> func);
} }
} }

View File

@@ -14,7 +14,7 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithClientIP([NotNull] params IMatcher[] matchers); IRequestBuilder WithClientIP([NotNull] params IStringMatcher[] matchers);
/// <summary> /// <summary>
/// The with ClientIP. /// The with ClientIP.

View File

@@ -12,7 +12,7 @@ namespace WireMock.RequestBuilders
public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder
{ {
/// <summary> /// <summary>
/// The with header. /// Add Header matching based on name, pattern and ignoreCase.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
@@ -20,20 +20,29 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, string pattern, bool ignoreCase = true); IRequestBuilder WithHeader([NotNull] string name, string pattern, bool ignoreCase = true);
/// <summary>
/// Add Header matching based on name, patterns and ignoreCase.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">ignore Case</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, string[] patterns, bool ignoreCase = true);
/// <summary> /// <summary>
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IMatcher[] matchers); IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IStringMatcher[] matchers);
/// <summary> /// <summary>
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="funcs">The headers funcs.</param> /// <param name="funcs">The headers funcs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string>, bool>[] funcs); IRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string[]>, bool>[] funcs);
/// <summary> /// <summary>
/// The with cookie. /// The with cookie.
@@ -50,7 +59,7 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IMatcher[] matchers); IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IStringMatcher[] matchers);
/// <summary> /// <summary>
/// The with cookie. /// The with cookie.

View File

@@ -7,6 +7,14 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
public interface IMethodRequestBuilder : IHeadersAndCookiesRequestBuilder public interface IMethodRequestBuilder : IHeadersAndCookiesRequestBuilder
{ {
/// <summary>
/// The using delete.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingDelete();
/// <summary> /// <summary>
/// The using get. /// The using get.
/// </summary> /// </summary>
@@ -15,6 +23,14 @@ namespace WireMock.RequestBuilders
/// </returns> /// </returns>
IRequestBuilder UsingGet(); IRequestBuilder UsingGet();
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingHead();
/// <summary> /// <summary>
/// The using post. /// The using post.
/// </summary> /// </summary>
@@ -24,12 +40,12 @@ namespace WireMock.RequestBuilders
IRequestBuilder UsingPost(); IRequestBuilder UsingPost();
/// <summary> /// <summary>
/// The using delete. /// The using patch.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// The <see cref="IRequestBuilder"/>. /// The <see cref="IRequestBuilder"/>.
/// </returns> /// </returns>
IRequestBuilder UsingDelete(); IRequestBuilder UsingPatch();
/// <summary> /// <summary>
/// The using put. /// The using put.
@@ -39,14 +55,6 @@ namespace WireMock.RequestBuilders
/// </returns> /// </returns>
IRequestBuilder UsingPut(); IRequestBuilder UsingPut();
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
IRequestBuilder UsingHead();
/// <summary> /// <summary>
/// The using any verb. /// The using any verb.
/// </summary> /// </summary>

View File

@@ -14,7 +14,7 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithPath([NotNull] params IMatcher[] matchers); IRequestBuilder WithPath([NotNull] params IStringMatcher[] matchers);
/// <summary> /// <summary>
/// The with path. /// The with path.
@@ -35,7 +35,7 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithUrl([NotNull] params IMatcher[] matchers); IRequestBuilder WithUrl([NotNull] params IStringMatcher[] matchers);
/// <summary> /// <summary>
/// The with url. /// The with url.

View File

@@ -59,9 +59,9 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithClientIP(params IMatcher[] matchers) public IRequestBuilder WithClientIP(params IStringMatcher[] matchers)
{ {
Check.NotEmpty(matchers, nameof(matchers)); Check.NotNullOrEmpty(matchers, nameof(matchers));
_requestMatchers.Add(new RequestMessageClientIPMatcher(matchers)); _requestMatchers.Add(new RequestMessageClientIPMatcher(matchers));
return this; return this;
@@ -74,7 +74,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithClientIP(params string[] clientIPs) public IRequestBuilder WithClientIP(params string[] clientIPs)
{ {
Check.NotEmpty(clientIPs, nameof(clientIPs)); Check.NotNullOrEmpty(clientIPs, nameof(clientIPs));
_requestMatchers.Add(new RequestMessageClientIPMatcher(clientIPs)); _requestMatchers.Add(new RequestMessageClientIPMatcher(clientIPs));
return this; return this;
@@ -87,7 +87,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithClientIP(params Func<string, bool>[] funcs) public IRequestBuilder WithClientIP(params Func<string, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessageClientIPMatcher(funcs)); _requestMatchers.Add(new RequestMessageClientIPMatcher(funcs));
return this; return this;
@@ -98,9 +98,9 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithPath(params IMatcher[] matchers) public IRequestBuilder WithPath(params IStringMatcher[] matchers)
{ {
Check.NotEmpty(matchers, nameof(matchers)); Check.NotNullOrEmpty(matchers, nameof(matchers));
_requestMatchers.Add(new RequestMessagePathMatcher(matchers)); _requestMatchers.Add(new RequestMessagePathMatcher(matchers));
return this; return this;
@@ -113,7 +113,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithPath(params string[] paths) public IRequestBuilder WithPath(params string[] paths)
{ {
Check.NotEmpty(paths, nameof(paths)); Check.NotNullOrEmpty(paths, nameof(paths));
_requestMatchers.Add(new RequestMessagePathMatcher(paths)); _requestMatchers.Add(new RequestMessagePathMatcher(paths));
return this; return this;
@@ -126,7 +126,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithPath(params Func<string, bool>[] funcs) public IRequestBuilder WithPath(params Func<string, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessagePathMatcher(funcs)); _requestMatchers.Add(new RequestMessagePathMatcher(funcs));
return this; return this;
@@ -137,9 +137,9 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithUrl(params IMatcher[] matchers) public IRequestBuilder WithUrl(params IStringMatcher[] matchers)
{ {
Check.NotEmpty(matchers, nameof(matchers)); Check.NotNullOrEmpty(matchers, nameof(matchers));
_requestMatchers.Add(new RequestMessageUrlMatcher(matchers)); _requestMatchers.Add(new RequestMessageUrlMatcher(matchers));
return this; return this;
@@ -152,7 +152,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithUrl(params string[] urls) public IRequestBuilder WithUrl(params string[] urls)
{ {
Check.NotEmpty(urls, nameof(urls)); Check.NotNullOrEmpty(urls, nameof(urls));
_requestMatchers.Add(new RequestMessageUrlMatcher(urls)); _requestMatchers.Add(new RequestMessageUrlMatcher(urls));
return this; return this;
@@ -165,76 +165,55 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithUrl(params Func<string, bool>[] funcs) public IRequestBuilder WithUrl(params Func<string, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessageUrlMatcher(funcs)); _requestMatchers.Add(new RequestMessageUrlMatcher(funcs));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IMethodRequestBuilder.UsingDelete"/>
/// The using get.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingGet()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("get"));
return this;
}
/// <summary>
/// The using post.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingPost()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("post"));
return this;
}
/// <summary>
/// The using put.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingPut()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("put"));
return this;
}
/// <summary>
/// The using delete.
/// </summary>
/// <returns>
/// The <see cref="IRequestBuilder"/>.
/// </returns>
public IRequestBuilder UsingDelete() public IRequestBuilder UsingDelete()
{ {
_requestMatchers.Add(new RequestMessageMethodMatcher("delete")); _requestMatchers.Add(new RequestMessageMethodMatcher("delete"));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IMethodRequestBuilder.UsingGet"/>
/// The using head. public IRequestBuilder UsingGet()
/// </summary> {
/// <returns>The <see cref="IRequestBuilder"/>.</returns> _requestMatchers.Add(new RequestMessageMethodMatcher("get"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingHead"/>
public IRequestBuilder UsingHead() public IRequestBuilder UsingHead()
{ {
_requestMatchers.Add(new RequestMessageMethodMatcher("head")); _requestMatchers.Add(new RequestMessageMethodMatcher("head"));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IMethodRequestBuilder.UsingPost"/>
/// The using any verb. public IRequestBuilder UsingPost()
/// </summary> {
/// <returns> _requestMatchers.Add(new RequestMessageMethodMatcher("post"));
/// The <see cref="IRequestBuilder"/>. return this;
/// </returns> }
/// <inheritdoc cref="IMethodRequestBuilder.UsingPatch"/>
public IRequestBuilder UsingPatch()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("patch"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingPut"/>
public IRequestBuilder UsingPut()
{
_requestMatchers.Add(new RequestMessageMethodMatcher("put"));
return this;
}
/// <inheritdoc cref="IMethodRequestBuilder.UsingAnyVerb"/>
public IRequestBuilder UsingAnyVerb() public IRequestBuilder UsingAnyVerb()
{ {
var matchers = _requestMatchers.Where(m => m is RequestMessageMethodMatcher).ToList(); var matchers = _requestMatchers.Where(m => m is RequestMessageMethodMatcher).ToList();
@@ -246,80 +225,37 @@ namespace WireMock.RequestBuilders
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IMethodRequestBuilder.UsingVerb"/>
/// The using verb.
/// </summary>
/// <param name="verbs">The verbs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder UsingVerb(params string[] verbs) public IRequestBuilder UsingVerb(params string[] verbs)
{ {
Check.NotEmpty(verbs, nameof(verbs)); Check.NotNullOrEmpty(verbs, nameof(verbs));
_requestMatchers.Add(new RequestMessageMethodMatcher(verbs)); _requestMatchers.Add(new RequestMessageMethodMatcher(verbs));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(string)"/>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(string body) public IRequestBuilder WithBody(string body)
{ {
_requestMatchers.Add(new RequestMessageBodyMatcher(body)); _requestMatchers.Add(new RequestMessageBodyMatcher(body));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(byte[])"/>
/// The with body byte[].
/// </summary>
/// <param name="body">
/// The body as byte[].
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(byte[] body) public IRequestBuilder WithBody(byte[] body)
{ {
_requestMatchers.Add(new RequestMessageBodyMatcher(body)); _requestMatchers.Add(new RequestMessageBodyMatcher(body));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(object)"/>
/// The with body. public IRequestBuilder WithBody(object body)
/// </summary>
/// <param name="func">
/// The body function.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(Func<string, bool> func)
{ {
Check.NotNull(func, nameof(func)); _requestMatchers.Add(new RequestMessageBodyMatcher(body));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(IMatcher)"/>
/// The with body.
/// </summary>
/// <param name="func">
/// The body function.
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithBody(Func<byte[], bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IRequestBuilder" />.</returns>
public IRequestBuilder WithBody(IMatcher matcher) public IRequestBuilder WithBody(IMatcher matcher)
{ {
Check.NotNull(matcher, nameof(matcher)); Check.NotNull(matcher, nameof(matcher));
@@ -328,16 +264,34 @@ namespace WireMock.RequestBuilders
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{string, bool})"/>
/// The with parameters. public IRequestBuilder WithBody(Func<string, bool> func)
/// </summary> {
/// <param name="key"> Check.NotNull(func, nameof(func));
/// The key.
/// </param> _requestMatchers.Add(new RequestMessageBodyMatcher(func));
/// <param name="values"> return this;
/// The values. }
/// </param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{byte[], bool})"/>
public IRequestBuilder WithBody(Func<byte[], bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{object, bool})"/>
public IRequestBuilder WithBody(Func<object, bool> func)
{
Check.NotNull(func, nameof(func));
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
return this;
}
/// <inheritdoc cref="IParamsRequestBuilder.WithParam(string, string[])"/>
public IRequestBuilder WithParam(string key, params string[] values) public IRequestBuilder WithParam(string key, params string[] values)
{ {
Check.NotNull(key, nameof(key)); Check.NotNull(key, nameof(key));
@@ -346,26 +300,16 @@ namespace WireMock.RequestBuilders
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IParamsRequestBuilder.WithParam(Func{IDictionary{string, WireMockList{string}}, bool}[])"/>
/// The with parameters.
/// </summary>
/// <param name="funcs">The funcs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs) public IRequestBuilder WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessageParamMatcher(funcs)); _requestMatchers.Add(new RequestMessageParamMatcher(funcs));
return this; return this;
} }
/// <summary> /// <inheritdoc cref="IHeadersAndCookiesRequestBuilder.WithHeader(string,string,bool)"/>
/// With header.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true) public IRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
@@ -375,16 +319,26 @@ namespace WireMock.RequestBuilders
return this; return this;
} }
/// <inheritdoc cref="IHeadersAndCookiesRequestBuilder.WithHeader(string,string[],bool)"/>
public IRequestBuilder WithHeader(string name, string[] patterns, bool ignoreCase = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(patterns, nameof(patterns));
_requestMatchers.Add(new RequestMessageHeaderMatcher(name, patterns, ignoreCase));
return this;
}
/// <summary> /// <summary>
/// With header. /// With header.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithHeader(string name, params IMatcher[] matchers) public IRequestBuilder WithHeader(string name, params IStringMatcher[] matchers)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotEmpty(matchers, nameof(matchers)); Check.NotNullOrEmpty(matchers, nameof(matchers));
_requestMatchers.Add(new RequestMessageHeaderMatcher(name, matchers)); _requestMatchers.Add(new RequestMessageHeaderMatcher(name, matchers));
return this; return this;
@@ -395,9 +349,9 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="funcs">The funcs.</param> /// <param name="funcs">The funcs.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithHeader(params Func<IDictionary<string, string>, bool>[] funcs) public IRequestBuilder WithHeader(params Func<IDictionary<string, string[]>, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessageHeaderMatcher(funcs)); _requestMatchers.Add(new RequestMessageHeaderMatcher(funcs));
return this; return this;
@@ -422,9 +376,9 @@ namespace WireMock.RequestBuilders
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithCookie(string name, params IMatcher[] matchers) public IRequestBuilder WithCookie(string name, params IStringMatcher[] matchers)
{ {
Check.NotEmpty(matchers, nameof(matchers)); Check.NotNullOrEmpty(matchers, nameof(matchers));
_requestMatchers.Add(new RequestMessageCookieMatcher(name, matchers)); _requestMatchers.Add(new RequestMessageCookieMatcher(name, matchers));
return this; return this;
@@ -437,7 +391,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IRequestBuilder"/>.</returns> /// <returns>The <see cref="IRequestBuilder"/>.</returns>
public IRequestBuilder WithCookie(params Func<IDictionary<string, string>, bool>[] funcs) public IRequestBuilder WithCookie(params Func<IDictionary<string, string>, bool>[] funcs)
{ {
Check.NotEmpty(funcs, nameof(funcs)); Check.NotNullOrEmpty(funcs, nameof(funcs));
_requestMatchers.Add(new RequestMessageCookieMatcher(funcs)); _requestMatchers.Add(new RequestMessageCookieMatcher(funcs));
return this; return this;

View File

@@ -1,137 +1,217 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using System.Text;
using WireMock.Util; using System.Net;
using WireMock.Validation; using JetBrains.Annotations;
using System.Text; using WireMock.Util;
using WireMock.Validation;
namespace WireMock
{ namespace WireMock
/// <summary> {
/// The request. /// <summary>
/// </summary> /// The request.
public class RequestMessage /// </summary>
{ public class RequestMessage
/// <summary> {
/// Gets the Client IP Address. /// <summary>
/// </summary> /// Gets the Client IP Address.
public string ClientIP { get; } /// </summary>
public string ClientIP { get; }
/// <summary>
/// Gets the url. /// <summary>
/// </summary> /// Gets the url.
public string Url { get; } /// </summary>
public string Url { get; }
/// <summary>
/// Gets the DateTime. /// <summary>
/// </summary> /// Gets the DateTime.
public DateTime DateTime { get; set; } /// </summary>
public DateTime DateTime { get; set; }
/// <summary>
/// Gets the path. /// <summary>
/// </summary> /// Gets the path.
public string Path { get; } /// </summary>
public string Path { get; }
/// <summary>
/// Gets the method. /// <summary>
/// </summary> /// Gets the method.
public string Method { get; } /// </summary>
public string Method { get; }
/// <summary>
/// Gets the headers. /// <summary>
/// </summary> /// Gets the headers.
public IDictionary<string, string> Headers { get; } /// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; }
/// <summary>
/// Gets the cookies. /// <summary>
/// </summary> /// Gets the cookies.
public IDictionary<string, string> Cookies { get; } /// </summary>
public IDictionary<string, string> Cookies { get; }
/// <summary>
/// Gets the query. /// <summary>
/// </summary> /// Gets the query.
public IDictionary<string, WireMockList<string>> Query { get; } = new Dictionary<string, WireMockList<string>>(); /// </summary>
public IDictionary<string, WireMockList<string>> Query { get; }
/// <summary>
/// Gets the bodyAsBytes. /// <summary>
/// </summary> /// Gets the raw query.
public byte[] BodyAsBytes { get; } /// </summary>
public string RawQuery { get; }
/// <summary>
/// Gets the body. /// <summary>
/// </summary> /// The body as string.
public string Body { get; } /// </summary>
public string Body { get; }
/// <summary>
/// Gets the body encoding. /// <summary>
/// </summary> /// The body (as JSON object).
public Encoding BodyEncoding { get; } /// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class. /// <summary>
/// </summary> /// The body (as bytearray).
/// <param name="url">The original url.</param> /// </summary>
/// <param name="method">The HTTP method.</param> public byte[] BodyAsBytes { get; set; }
/// <param name="clientIP">The client IP Address.</param>
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param> /// <summary>
/// <param name="body">The body string.</param> /// Gets the Host
/// <param name="bodyEncoding">The body encoding</param> /// </summary>
/// <param name="headers">The headers.</param> public string Host { get; }
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] Encoding bodyEncoding = null, [CanBeNull] IDictionary<string, string> headers = null, [CanBeNull] IDictionary<string, string> cookies = null) /// <summary>
{ /// Gets the protocol
Check.NotNull(url, nameof(url)); /// </summary>
Check.NotNull(method, nameof(method)); public string Protocol { get; }
Check.NotNull(clientIP, nameof(clientIP));
/// <summary>
Url = url.ToString(); /// Gets the port
Path = url.AbsolutePath; /// </summary>
Method = method.ToLower(); public int Port { get; }
ClientIP = clientIP;
BodyAsBytes = bodyAsBytes; /// <summary>
Body = body; /// Gets the origin
BodyEncoding = bodyEncoding; /// </summary>
Headers = headers; public string Origin { get; }
Cookies = cookies;
/// <summary>
string query = url.Query; /// The body encoding.
if (!string.IsNullOrEmpty(query)) /// </summary>
{ public Encoding BodyEncoding { get; }
if (query.StartsWith("?"))
{ /// <summary>
query = query.Substring(1); /// Initializes a new instance of the <see cref="RequestMessage"/> class.
} /// </summary>
/// <param name="url">The original url.</param>
Query = query.Split('&').Aggregate( /// <param name="method">The HTTP method.</param>
new Dictionary<string, WireMockList<string>>(), /// <param name="clientIP">The client IP Address.</param>
(dict, term) => /// <param name="body">The body.</param>
{ /// <param name="headers">The headers.</param>
var parts = term.Split('='); /// <param name="cookies">The cookies.</param>
string key = parts[0]; public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] BodyData body, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
if (!dict.ContainsKey(key)) {
{ Check.NotNull(url, nameof(url));
dict.Add(key, new WireMockList<string>()); Check.NotNull(method, nameof(method));
} Check.NotNull(clientIP, nameof(clientIP));
if (parts.Length == 2) Url = url.ToString();
{ Protocol = url.Scheme;
dict[key].Add(parts[1]); Host = url.Host;
} Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
return dict; Path = WebUtility.UrlDecode(url.AbsolutePath);
}); Method = method.ToLower();
} ClientIP = clientIP;
}
Body = body?.BodyAsString;
/// <summary> BodyEncoding = body?.Encoding;
/// The get a query parameter. BodyAsJson = body?.BodyAsJson;
/// </summary> BodyAsBytes = body?.BodyAsBytes;
/// <param name="key">The key.</param>
/// <returns>The query parameter.</returns> Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
public List<string> GetParameter(string key) Cookies = cookies;
{ RawQuery = WebUtility.UrlDecode(url.Query);
return Query.ContainsKey(key) ? Query[key] : null; Query = ParseQuery(RawQuery);
} }
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param>
/// <param name="body">The body string.</param>
/// <param name="bodyEncoding">The body encoding</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] Encoding bodyEncoding = null, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));
Url = url.ToString();
Protocol = url.Scheme;
Host = url.Host;
Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
Path = WebUtility.UrlDecode(url.AbsolutePath);
Method = method.ToLower();
ClientIP = clientIP;
BodyAsBytes = bodyAsBytes;
Body = body;
BodyEncoding = bodyEncoding;
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = WebUtility.UrlDecode(url.Query);
Query = ParseQuery(RawQuery);
}
private static IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
{
if (string.IsNullOrEmpty(queryString))
{
return null;
}
if (queryString.StartsWith("?"))
{
queryString = queryString.Substring(1);
}
return queryString.Split('&').Aggregate(new Dictionary<string, WireMockList<string>>(),
(dict, term) =>
{
var parts = term.Split('=');
string key = parts[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new WireMockList<string>());
}
if (parts.Length == 2)
{
dict[key].Add(parts[1]);
}
return dict;
});
}
/// <summary>
/// Get a query parameter.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>The query parameter.</returns>
public List<string> GetParameter(string key)
{
if (Query == null)
{
return null;
}
return Query.ContainsKey(key) ? Query[key] : null;
}
}
} }

View File

@@ -0,0 +1,23 @@
namespace WireMock.ResponseBuilders
{
/// <summary>
/// Defines the BodyDestinationFormat
/// </summary>
public static class BodyDestinationFormat
{
/// <summary>
/// Same as source (no conversion)
/// </summary>
public const string SameAsSource = "SameAsSource";
/// <summary>
/// Convert to string
/// </summary>
public const string String = "String";
/// <summary>
/// Convert to bytes
/// </summary>
public const string Bytes = "Bytes";
}
}

View File

@@ -1,4 +1,5 @@
using System.Text; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
@@ -9,15 +10,36 @@ namespace WireMock.ResponseBuilders
public interface IBodyResponseBuilder : ITransformResponseBuilder public interface IBodyResponseBuilder : ITransformResponseBuilder
{ {
/// <summary> /// <summary>
/// The with body. /// WithBody : Create a ... response based on a string.
/// </summary> /// </summary>
/// <param name="body">The body.</param> /// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param> /// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] string body, [CanBeNull] Encoding encoding = null); IResponseBuilder WithBody([NotNull] string body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary> /// <summary>
/// The with body as Json. /// WithBody : Create a ... response based on a callback function.
/// </summary>
/// <param name="bodyFactory">The delegate to build the body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] Func<RequestMessage,string> bodyFactory, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBody : Create a ... response based on a bytearray.
/// </summary>
/// <param name="body">The body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBody([NotNull] byte[] body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBody : Create a string response based on a object (which will be converted to a JSON string).
/// </summary> /// </summary>
/// <param name="body">The body.</param> /// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param> /// <param name="encoding">The body encoding.</param>
@@ -25,11 +47,20 @@ namespace WireMock.ResponseBuilders
IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null); IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null);
/// <summary> /// <summary>
/// The with body as base64. /// WithBody : Create a string response based on a Base64 string (which will be decoded to a normal string).
/// </summary> /// </summary>
/// <param name="bodyAsbase64">The body asbase64.</param> /// <param name="bodyAsbase64">The body.</param>
/// <param name="encoding">The Encoding.</param> /// <param name="encoding">The Encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null); [Obsolete]
IResponseBuilder WithBodyFromBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null);
/// <summary>
/// WithBodyFromFile : Create a ... response based on a File.
/// </summary>
/// <param name="filename">The filename.</param>
/// <param name="cache">Defines if this file is cached in memory or retrieved from disk everytime the response is created.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyFromFile([NotNull] string filename, bool cache = true);
} }
} }

View File

@@ -0,0 +1,19 @@
using System;
using JetBrains.Annotations;
using WireMock.ResponseProviders;
namespace WireMock.ResponseBuilders
{
/// <summary>
/// The CallbackResponseBuilder interface.
/// </summary>
public interface ICallbackResponseBuilder : IResponseProvider
{
/// <summary>
/// The callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<RequestMessage, ResponseMessage> callbackHandler);
}
}

View File

@@ -5,7 +5,7 @@ namespace WireMock.ResponseBuilders
/// <summary> /// <summary>
/// The DelayResponseBuilder interface. /// The DelayResponseBuilder interface.
/// </summary> /// </summary>
public interface IDelayResponseBuilder : IResponseProvider public interface IDelayResponseBuilder : ICallbackResponseBuilder
{ {
/// <summary> /// <summary>
/// The with delay. /// The with delay.

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Util;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
{ {
@@ -12,15 +13,29 @@ namespace WireMock.ResponseBuilders
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="value">The value.</param> /// <param name="values">The values.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns> /// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeader([NotNull] string name, string value); IResponseBuilder WithHeader([NotNull] string name, params string[] values);
/// <summary> /// <summary>
/// The with headers. /// The with headers.
/// </summary> /// </summary>
/// <param name="headers">The headers.</param> /// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns> /// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string,string> headers); IResponseBuilder WithHeaders([NotNull] IDictionary<string, string> headers);
/// <summary>
/// The with headers.
/// </summary>
/// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string, string[]> headers);
/// <summary>
/// The with headers.
/// </summary>
/// <param name="headers">The headers.</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithHeaders([NotNull] IDictionary<string, WireMockList<string>> headers);
} }
} }

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Settings;
namespace WireMock.ResponseBuilders namespace WireMock.ResponseBuilders
{ {
@@ -8,11 +9,18 @@ namespace WireMock.ResponseBuilders
public interface IProxyResponseBuilder : IStatusCodeResponseBuilder public interface IProxyResponseBuilder : IStatusCodeResponseBuilder
{ {
/// <summary> /// <summary>
/// With Proxy URL using X509Certificate2. /// WithProxy URL using Client X509Certificate2.
/// </summary> /// </summary>
/// <param name="proxyUrl">The proxy url.</param> /// <param name="proxyUrl">The proxy url.</param>
/// <param name="clientX509Certificate2ThumbprintOrSubjectName">The X509Certificate2 file to use for client authentication.</param> /// <param name="clientX509Certificate2ThumbprintOrSubjectName">The X509Certificate2 file to use for client authentication.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithProxy([NotNull] string proxyUrl, [CanBeNull] string clientX509Certificate2ThumbprintOrSubjectName = null); IResponseBuilder WithProxy([NotNull] string proxyUrl, [CanBeNull] string clientX509Certificate2ThumbprintOrSubjectName = null);
/// <summary>
/// WithProxy using IProxyAndRecordSettings.
/// </summary>
/// <param name="settings">The IProxyAndRecordSettings.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithProxy([NotNull] IProxyAndRecordSettings settings);
} }
} }

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