ExactMatcher doesn't respect special characters #206

Closed
opened 2025-12-29 14:25:05 +01:00 by adam · 8 comments
Owner

Originally created by @PkAIR on GitHub (Aug 27, 2019).

For a pattern with regex special character (e.g. brackets) ExactMather works unexpectedly.

I'm having this simple mapping:

[
    {
        "Guid": "f781912f-fc5d-4f59-ad9a-e7e8847ab197",
        "Scenario": "Test For 123",
        "SetStateTo": "1",
        "Request": {
            "Path": {
                "Matchers": [
                    {
                        "Name": "WildcardMatcher",
                        "Pattern": "*/ChangePortfolio",
                        "IgnoreCase": false
                    }
                ]
            },
            "Url": {
                "Matchers": [
                    {
                        "Name": "ExactMatcher",
                        "Pattern": "http://localhost:9999/Transactions(123)/ChangePortfolio"
                    }
                ]
            },
            "Methods": [
                "POST"
            ],
            "Body": {
                "Matcher": {
                    "Name": "WildcardMatcher",
                    "Pattern": "*",
                    "IgnoreCase": false
                }
            }
        },
        "Response": {
            "StatusCode": 200,
            "Headers": {
                "test": "test"
            }
        }
    }
]

And with simple post request http://localhost:9999/Transactions(123)/ChangePortfolio having 'No matching mapping found' message.

When I try to escape '(' symbol using \ preceding symbol I receive this mapping:

[
    {
        "Guid": "2ad5f360-4e79-47e4-a2f7-51dfca7a3511",
        "Scenario": "Test For 123",
        "SetStateTo": "1",
        "Request": {
            "Path": {
                "Matchers": [
                    {
                        "Name": "WildcardMatcher",
                        "Pattern": "*/ChangePortfolio",
                        "IgnoreCase": false
                    }
                ]
            },
            "Url": {
                "Matchers": [
                    {
                        "Name": "ExactMatcher",
                        "Pattern": "http://localhost:9999/Transactions\\(123\\)/ChangePortfolio"
                    }
                ]
            },
            "Methods": [
                "POST"
            ],
            "Body": {
                "Matcher": {
                    "Name": "WildcardMatcher",
                    "Pattern": "*",
                    "IgnoreCase": false
                }
            }
        },
        "Response": {
            "StatusCode": 200,
            "Headers": {
                "test": "test"
            }
        }
    }
]

Same for

"Url": {
                "Matchers": [
                    {
                        "Name": "ExactMatcher",
                        "Pattern": "http://localhost:9999/Transactions~123~/ChangePortfolio"
                    }
                ]
            }

and http://localhost:9999/Transactions123/ChangePortfolio

How should I escape symbols like brackets, !, ~ etc?

Originally created by @PkAIR on GitHub (Aug 27, 2019). For a pattern with regex special character (e.g. brackets) **ExactMather** works unexpectedly. I'm having this simple mapping: ```json [ { "Guid": "f781912f-fc5d-4f59-ad9a-e7e8847ab197", "Scenario": "Test For 123", "SetStateTo": "1", "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "*/ChangePortfolio", "IgnoreCase": false } ] }, "Url": { "Matchers": [ { "Name": "ExactMatcher", "Pattern": "http://localhost:9999/Transactions(123)/ChangePortfolio" } ] }, "Methods": [ "POST" ], "Body": { "Matcher": { "Name": "WildcardMatcher", "Pattern": "*", "IgnoreCase": false } } }, "Response": { "StatusCode": 200, "Headers": { "test": "test" } } } ] ``` And with simple post request http://localhost:9999/Transactions(123)/ChangePortfolio having 'No matching mapping found' message. When I try to escape '(' symbol using \ preceding symbol I receive this mapping: ```json [ { "Guid": "2ad5f360-4e79-47e4-a2f7-51dfca7a3511", "Scenario": "Test For 123", "SetStateTo": "1", "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "*/ChangePortfolio", "IgnoreCase": false } ] }, "Url": { "Matchers": [ { "Name": "ExactMatcher", "Pattern": "http://localhost:9999/Transactions\\(123\\)/ChangePortfolio" } ] }, "Methods": [ "POST" ], "Body": { "Matcher": { "Name": "WildcardMatcher", "Pattern": "*", "IgnoreCase": false } } }, "Response": { "StatusCode": 200, "Headers": { "test": "test" } } } ] ``` Same for ```json "Url": { "Matchers": [ { "Name": "ExactMatcher", "Pattern": "http://localhost:9999/Transactions~123~/ChangePortfolio" } ] } ``` and http://localhost:9999/Transactions~123~/ChangePortfolio How should I escape symbols like brackets, !, ~ etc?
adam added the question label 2025-12-29 14:25:05 +01:00
adam closed this issue 2025-12-29 14:25:05 +01:00
Author
Owner

@StefH commented on GitHub (Aug 27, 2019):

  1. No need to escape these characters.

  2. I see you are using Path and Url matchers, it's best to just use one. And make sure the http://localhost:9999 is the location where WireMock.Net is running.

  3. If you want more details, you can call http://{{wm_hostname}}/__admin/requests to see all requests + the RequestMatchResult which shows you which items do match. Maybe in your case the body is not matched correctly?

@StefH commented on GitHub (Aug 27, 2019): 1. No need to escape these characters. 2. I see you are using Path and Url matchers, it's best to just use one. And make sure the http://localhost:9999 is the location where WireMock.Net is running. 3. If you want more details, you can call `http://{{wm_hostname}}/__admin/requests` to see all requests + the **RequestMatchResult** which shows you which items do match. Maybe in your case the body is not matched correctly?
Author
Owner

@PkAIR commented on GitHub (Aug 27, 2019):

  1. Well, I got it that I don't need to escape character.

  2. Not sure what the issue using both of them. I know that it's sort of overkill but nevertheless. And yeah, http://localhost:9999 is the hostname for my wiremock.

  3. I'll check but in my case body matcher is a wildcaard one with * as value. Additionally when I use url without brackets smth like http://localhost:9999/Transactions123/ChangePortfolio it works.

@PkAIR commented on GitHub (Aug 27, 2019): 1. Well, I got it that I don't need to escape character. 2. Not sure what the issue using both of them. I know that it's sort of overkill but nevertheless. And yeah, http://localhost:9999 is the hostname for my wiremock. 3. I'll check but in my case body matcher is a wildcaard one with * as value. Additionally when I use url without brackets smth like http://localhost:9999/Transactions123/ChangePortfolio it works.
Author
Owner

@StefH commented on GitHub (Aug 27, 2019):

  1. If you can, please post the **RequestMatchResult ** here.

And which application do you use to post the request ? (I did test using Postman)

image

And the match result is like:

"RequestMatchResult": {
      "TotalScore": 3.0,
      "TotalNumber": 3,
      "IsPerfectMatch": true,
      "AverageTotalScore": 1.0,
      "MatchDetails": [
        {
          "Name": "PathMatcher",
          "Score": 1.0
        },
        {
          "Name": "MethodMatcher",
          "Score": 1.0
        },
        {
          "Name": "BodyMatcher",
          "Score": 1.0
        }
      ]
    }

It seems that only the PathMatcher is used, this could be business logic from WireMock...

@StefH commented on GitHub (Aug 27, 2019): 3. If you can, please post the **RequestMatchResult ** here. And which application do you use to post the request ? (I did test using Postman) ![image](https://user-images.githubusercontent.com/249938/63788972-aeb33180-c8f6-11e9-8174-83cefc47cbe5.png) And the match result is like: ``` c# "RequestMatchResult": { "TotalScore": 3.0, "TotalNumber": 3, "IsPerfectMatch": true, "AverageTotalScore": 1.0, "MatchDetails": [ { "Name": "PathMatcher", "Score": 1.0 }, { "Name": "MethodMatcher", "Score": 1.0 }, { "Name": "BodyMatcher", "Score": 1.0 } ] } ``` It seems that only the PathMatcher is used, this could be business logic from WireMock...
Author
Owner

@PkAIR commented on GitHub (Aug 27, 2019):

Well,

Firstly I tried /__admin/requests for url without brackets (and yes, I've use Postman also for tests):

image

image

[
    {
        "Guid": "b8eb7e2c-1397-4d3b-8ef9-e4fbcf744539",
        "Request": {
            "ClientIP": "127.0.0.1",
            "DateTime": "2019-08-27T16:30:03.7930825Z",
            "Path": "/Transactions123/ChangePortfolio",
            "AbsolutePath": "/Transactions123/ChangePortfolio",
            "Url": "http://localhost:9999/Transactions123/ChangePortfolio",
            "AbsoluteUrl": "http://localhost:9999/Transactions123/ChangePortfolio",
            "Query": {},
            "Method": "POST",
            "Headers": {
                "Postman-Token": [
                    "e82f9454-4589-4ec4-95fc-1e53455c6c89"
                ],
                "Cache-Control": [
                    "no-cache"
                ],
                "Connection": [
                    "keep-alive"
                ],
                "Content-Length": [
                    "1"
                ],
                "Content-Type": [
                    "text/plain"
                ],
                "Accept": [
                    "*/*"
                ],
                "Accept-Encoding": [
                    "gzip, deflate"
                ],
                "Host": [
                    "localhost:9999"
                ],
                "User-Agent": [
                    "PostmanRuntime/7.4.0"
                ]
            },
            "Body": "a",
            "BodyEncoding": {
                "CodePage": 65001,
                "EncodingName": "Unicode (UTF-8)",
                "WebName": "utf-8"
            },
            "DetectedBodyType": "String",
            "DetectedBodyTypeFromContentType": "String"
        },
        "Response": {
            "StatusCode": 200,
            "Headers": {
                "test": [
                    "test"
                ]
            },
            "DetectedBodyType": 0,
            "DetectedBodyTypeFromContentType": 0
        },
        "MappingGuid": "98002537-5500-4a49-b673-5555875af78c",
        "RequestMatchResult": {
            "TotalScore": 5,
            "TotalNumber": 5,
            "IsPerfectMatch": true,
            "AverageTotalScore": 1,
            "MatchDetails": [
                {
                    "Name": "MethodMatcher",
                    "Score": 1
                },
                {
                    "Name": "BodyMatcher",
                    "Score": 1
                },
                {
                    "Name": "PathMatcher",
                    "Score": 1
                },
                {
                    "Name": "UrlMatcher",
                    "Score": 1
                },
                {
                    "Name": "ScenarioAndStateMatcher",
                    "Score": 1
                }
            ]
        }
    }
]

After that tried with brackets and result of /__admin/requests is:

[
    {
        "Guid": "769edea6-c8fc-41d5-b6c2-a1aad09b1ffd",
        "Request": {
            "ClientIP": "::1",
            "DateTime": "2019-08-27T16:26:57.0877553Z",
            "Path": "/Transactions(123)/ChangePortfolio",
            "AbsolutePath": "/Transactions(123)/ChangePortfolio",
            "Url": "http://localhost:9999/Transactions%28123%29/ChangePortfolio",
            "AbsoluteUrl": "http://localhost:9999/Transactions%28123%29/ChangePortfolio",
            "Query": {},
            "Method": "POST",
            "Headers": {
                "Postman-Token": [
                    "13f352d2-afa0-4a76-81f7-6d996e440cbf"
                ],
                "Cache-Control": [
                    "no-cache"
                ],
                "Connection": [
                    "keep-alive"
                ],
                "Content-Length": [
                    "1"
                ],
                "Content-Type": [
                    "text/plain"
                ],
                "Accept": [
                    "*/*"
                ],
                "Accept-Encoding": [
                    "gzip, deflate"
                ],
                "Host": [
                    "localhost:9999"
                ],
                "User-Agent": [
                    "PostmanRuntime/7.4.0"
                ]
            },
            "Body": "a",
            "BodyEncoding": {
                "CodePage": 65001,
                "EncodingName": "Unicode (UTF-8)",
                "WebName": "utf-8"
            },
            "DetectedBodyType": "String",
            "DetectedBodyTypeFromContentType": "String"
        },
        "Response": {
            "StatusCode": 404,
            "Headers": {
                "Content-Type": [
                    "application/json"
                ]
            },
            "BodyAsJson": {
                "Status": "No matching mapping found"
            },
            "DetectedBodyType": 2,
            "DetectedBodyTypeFromContentType": 0
        }
    }
]
@PkAIR commented on GitHub (Aug 27, 2019): Well, Firstly I tried /__admin/requests for url without brackets (and yes, I've use Postman also for tests): ![image](https://user-images.githubusercontent.com/30795278/63789821-cd1e2a80-c900-11e9-9cfc-9a0dd1927c38.png) ![image](https://user-images.githubusercontent.com/30795278/63789834-d3aca200-c900-11e9-902e-ba471f8bf65a.png) ```json [ { "Guid": "b8eb7e2c-1397-4d3b-8ef9-e4fbcf744539", "Request": { "ClientIP": "127.0.0.1", "DateTime": "2019-08-27T16:30:03.7930825Z", "Path": "/Transactions123/ChangePortfolio", "AbsolutePath": "/Transactions123/ChangePortfolio", "Url": "http://localhost:9999/Transactions123/ChangePortfolio", "AbsoluteUrl": "http://localhost:9999/Transactions123/ChangePortfolio", "Query": {}, "Method": "POST", "Headers": { "Postman-Token": [ "e82f9454-4589-4ec4-95fc-1e53455c6c89" ], "Cache-Control": [ "no-cache" ], "Connection": [ "keep-alive" ], "Content-Length": [ "1" ], "Content-Type": [ "text/plain" ], "Accept": [ "*/*" ], "Accept-Encoding": [ "gzip, deflate" ], "Host": [ "localhost:9999" ], "User-Agent": [ "PostmanRuntime/7.4.0" ] }, "Body": "a", "BodyEncoding": { "CodePage": 65001, "EncodingName": "Unicode (UTF-8)", "WebName": "utf-8" }, "DetectedBodyType": "String", "DetectedBodyTypeFromContentType": "String" }, "Response": { "StatusCode": 200, "Headers": { "test": [ "test" ] }, "DetectedBodyType": 0, "DetectedBodyTypeFromContentType": 0 }, "MappingGuid": "98002537-5500-4a49-b673-5555875af78c", "RequestMatchResult": { "TotalScore": 5, "TotalNumber": 5, "IsPerfectMatch": true, "AverageTotalScore": 1, "MatchDetails": [ { "Name": "MethodMatcher", "Score": 1 }, { "Name": "BodyMatcher", "Score": 1 }, { "Name": "PathMatcher", "Score": 1 }, { "Name": "UrlMatcher", "Score": 1 }, { "Name": "ScenarioAndStateMatcher", "Score": 1 } ] } } ] ``` After that tried with brackets and result of /__admin/requests is: ```json [ { "Guid": "769edea6-c8fc-41d5-b6c2-a1aad09b1ffd", "Request": { "ClientIP": "::1", "DateTime": "2019-08-27T16:26:57.0877553Z", "Path": "/Transactions(123)/ChangePortfolio", "AbsolutePath": "/Transactions(123)/ChangePortfolio", "Url": "http://localhost:9999/Transactions%28123%29/ChangePortfolio", "AbsoluteUrl": "http://localhost:9999/Transactions%28123%29/ChangePortfolio", "Query": {}, "Method": "POST", "Headers": { "Postman-Token": [ "13f352d2-afa0-4a76-81f7-6d996e440cbf" ], "Cache-Control": [ "no-cache" ], "Connection": [ "keep-alive" ], "Content-Length": [ "1" ], "Content-Type": [ "text/plain" ], "Accept": [ "*/*" ], "Accept-Encoding": [ "gzip, deflate" ], "Host": [ "localhost:9999" ], "User-Agent": [ "PostmanRuntime/7.4.0" ] }, "Body": "a", "BodyEncoding": { "CodePage": 65001, "EncodingName": "Unicode (UTF-8)", "WebName": "utf-8" }, "DetectedBodyType": "String", "DetectedBodyTypeFromContentType": "String" }, "Response": { "StatusCode": 404, "Headers": { "Content-Type": [ "application/json" ] }, "BodyAsJson": { "Status": "No matching mapping found" }, "DetectedBodyType": 2, "DetectedBodyTypeFromContentType": 0 } } ] ```
Author
Owner

@StefH commented on GitHub (Aug 28, 2019):

Which .NET version do you use? Because on .NET Core 2.x, I see another detail in the request:
"Url": "http://localhost:9091/Transactions(123)/ChangePortfolio", (no %28 and %29)?

{
    "Guid": "10fbdf2e-b355-4c8b-804d-6b0fa6bb3dbc",
    "Request": {
      "ClientIP": "127.0.0.1",
      "DateTime": "2019-08-28T06:28:10.8547457Z",
      "Path": "/Transactions(123)/ChangePortfolio",
      "AbsolutePath": "/Transactions(123)/ChangePortfolio",
      "Url": "http://localhost:9091/Transactions(123)/ChangePortfolio",
      "AbsoluteUrl": "http://localhost:9091/Transactions(123)/ChangePortfolio",
      "Query": {},
      "Method": "POST",
      "Headers": {
        "Cache-Control": [
          "no-cache"
        ],
        "Connection": [
          "keep-alive"
        ],
        "Content-Type": [
          "text/plain"
        ],
        "Accept": [
          "*/*"
        ],
        "Accept-Encoding": [
          "gzip, deflate"
        ],
        "Authorization": [
          "Basic YTpi"
        ],
        "Host": [
          "localhost:9091"
        ],
        "User-Agent": [
          "PostmanRuntime/7.15.2"
        ],
        "Content-Length": [
          "1"
        ],
        "Postman-Token": [
          "1b0bb60c-2bea-442f-b312-2c1c3d509055"
        ]
      },
      "Body": "x",
      "BodyEncoding": {
        "CodePage": 65001,
        "EncodingName": "Unicode (UTF-8)",
        "WebName": "utf-8"
      },
      "DetectedBodyType": "String",
      "DetectedBodyTypeFromContentType": "String"
    },
    "Response": {
      "StatusCode": 200,
      "Headers": {
        "test": [
          "test"
        ]
      },
      "DetectedBodyType": 0,
      "DetectedBodyTypeFromContentType": 0
    },
    "MappingGuid": "f781912f-fc5d-4f59-ad9a-e7e8847ab197",
    "RequestMatchResult": {
      "TotalScore": 3.0,
      "TotalNumber": 3,
      "IsPerfectMatch": true,
      "AverageTotalScore": 1.0,
      "MatchDetails": [
        {
          "Name": "PathMatcher",
          "Score": 1.0
        },
        {
          "Name": "MethodMatcher",
          "Score": 1.0
        },
        {
          "Name": "BodyMatcher",
          "Score": 1.0
        }
      ]
    }
  }

What you also can do is allow-partial mapping, then the best match will be returned, so when looking at the requests you can maybe see more why a mapping doe snot match 100%

@StefH commented on GitHub (Aug 28, 2019): Which .NET version do you use? Because on .NET Core 2.x, I see another detail in the request: **"Url": "http://localhost:9091/Transactions(123)/ChangePortfolio",** (no `%28` and `%29`)? ``` js { "Guid": "10fbdf2e-b355-4c8b-804d-6b0fa6bb3dbc", "Request": { "ClientIP": "127.0.0.1", "DateTime": "2019-08-28T06:28:10.8547457Z", "Path": "/Transactions(123)/ChangePortfolio", "AbsolutePath": "/Transactions(123)/ChangePortfolio", "Url": "http://localhost:9091/Transactions(123)/ChangePortfolio", "AbsoluteUrl": "http://localhost:9091/Transactions(123)/ChangePortfolio", "Query": {}, "Method": "POST", "Headers": { "Cache-Control": [ "no-cache" ], "Connection": [ "keep-alive" ], "Content-Type": [ "text/plain" ], "Accept": [ "*/*" ], "Accept-Encoding": [ "gzip, deflate" ], "Authorization": [ "Basic YTpi" ], "Host": [ "localhost:9091" ], "User-Agent": [ "PostmanRuntime/7.15.2" ], "Content-Length": [ "1" ], "Postman-Token": [ "1b0bb60c-2bea-442f-b312-2c1c3d509055" ] }, "Body": "x", "BodyEncoding": { "CodePage": 65001, "EncodingName": "Unicode (UTF-8)", "WebName": "utf-8" }, "DetectedBodyType": "String", "DetectedBodyTypeFromContentType": "String" }, "Response": { "StatusCode": 200, "Headers": { "test": [ "test" ] }, "DetectedBodyType": 0, "DetectedBodyTypeFromContentType": 0 }, "MappingGuid": "f781912f-fc5d-4f59-ad9a-e7e8847ab197", "RequestMatchResult": { "TotalScore": 3.0, "TotalNumber": 3, "IsPerfectMatch": true, "AverageTotalScore": 1.0, "MatchDetails": [ { "Name": "PathMatcher", "Score": 1.0 }, { "Name": "MethodMatcher", "Score": 1.0 }, { "Name": "BodyMatcher", "Score": 1.0 } ] } } ``` What you also can do is allow-partial mapping, then the best match will be returned, so when looking at the requests you can maybe see more why a mapping doe snot match 100%
Author
Owner

@PkAIR commented on GitHub (Aug 28, 2019):

Ah, my bad. I was using 4.5.2.

Sounds fair for partial mapping to be used. Will try.

Thank you @StefH for your input btw.

@PkAIR commented on GitHub (Aug 28, 2019): Ah, my bad. I was using 4.5.2. Sounds fair for partial mapping to be used. Will try. Thank you @StefH for your input btw.
Author
Owner

@StefH commented on GitHub (Aug 28, 2019):

I need to debug some more, but if .net 4.5.2 and .net core behave different on the Url property, I have to fix this.

@StefH commented on GitHub (Aug 28, 2019): I need to debug some more, but if .net 4.5.2 and .net core behave different on the `Url` property, I have to fix this.
Author
Owner

@StefH commented on GitHub (Dec 7, 2019):

@PkAIR

Maybe fixed, can you please test version WireMock.Net.1.0.38-ci-12272.nupkg from MyGet?

@StefH commented on GitHub (Dec 7, 2019): @PkAIR Maybe fixed, can you please test version `WireMock.Net.1.0.38-ci-12272.nupkg` from MyGet?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#206