MimePartMatcher does not match multipart/form-data request body (possible bug?) #721

Open
opened 2025-12-29 08:32:58 +01:00 by adam · 4 comments
Owner

Originally created by @BrunoBeraud on GitHub (Oct 24, 2025).

Originally assigned to: @StefH on GitHub.

Hello,
First of all, thank you for this library — it helps us a lot in our development work!

I'm using WireMock.Net.Testcontainers 1.15.0 for our tests and the sheyenrath/wiremock.net-alpine:1.15.0 Docker image in our development environment.
We want to define a stub endpoint that accepts a multipart/form-data HTTP request.

Unfortunately, we’re not able to create a request body matcher using MimePartMatcher in a JSON mapping file.


What Works

This body matcher works correctly:

"Body": {
  "Matcher": {
    "Name": "RegexMatcher",
    "Pattern": ".+"
  }
}

What Doesn’t Work

When using MimePartMatcher, even with very lenient matchers, the matcher always returns a 0.0 score for the body:

"Body": {
  "Matcher": {
    "Name": "MimePartMatcher",
    "ContentTypeMatcher": {
      "Name": "RegexMatcher",
      "Pattern": ".*"
    },
    "ContentDispositionMatcher": {
      "Name": "RegexMatcher",
      "Pattern": ".*"
    },
    "ContentMatcher": {
      "Name": "RegexMatcher",
      "Pattern": ".*"
    }
  }
}

I also tried:

  • WildcardMatcher with * for all matchers
  • JsonMatcher with the exact JSON sent
  • JsonPartialMatcher using regex (with "Regex": true) and .* for all JSON values
  • Setting "ContentTypeMatcher" with "Name": "ContentTypeMatcher" and "Pattern": "application/json"

→ Always a 0.0 score for BodyMatcher (while PathMatcher, MethodMatcher, and HeadersMatcher all score 1.0).


Request Example

Here’s a sample curl request (exported from Postman):

curl -L -X POST "http://localhost:8080/my-stub-endpoint" \
  -F "metadata=\"{\\\"ID\\\": \\\"9858013b-e020-4ef9-b8a8-0bebc740e6a7\\\", \\\"DATE\\\": \\\"2025-08-15T13:45:30.0000000Z\\\", \\\"NAME\\\": \\\"32c9a8dd-e214-4afb-9611-9cde81f827c6\\\", \\\"NUMBER\\\": 10}\";type=application/json"

Observation

From the /__admin/requests endpoint, here’s an example of the request body WireMock receives:

"Headers": {
        "Accept": [
          "*/*"
        ],
        "Host": [
          "localhost:8080"
        ],
        "User-Agent": [
          "curl/8.13.0"
        ],
        "Content-Type": [
          "multipart/form-data; boundary=------------------------woli8b80pw4vBJtNpAMOKS"
        ],
        "Content-Length": [
          "334"
        ]
      },
"Body": "--------------------------woli8b80pw4vBJtNpAMOKS\r\n
Content-Disposition: form-data; name=\"metadata\"\r\n
Content-Type: application/json\r\n
\r\n
{\"ID\": \"9858013b-e020-4ef9-b8a8-0bebc740e6a7\", \"DATE\": \"2025-08-15T13:45:30.0000000Z\", \"NAME\": \"32c9a8dd-e214-4afb-9611-9cde81f827c6\", \"NUMBER\": 10}\r\n
--------------------------woli8b80pw4vBJtNpAMOKS--\r\n"

After digging a bit into the code, it seems that the issue comes from the use of the MimeKit library, which appears unable to parse this request body.
As a result, WireMock fails to extract the body parts, and the matcher score stays at its default value (0.0).


Possible Root Cause

It looks like the body content doesn’t include headers (such as Content-Type with a boundary) that would allow MimeKit to properly parse it into BodyParts.
In real HTTP requests, this header is not part of the body — it’s in the request headers — which might explain the mismatch compared to the examples in MimePartMatcherTests, where the content type is included in the body.


Question

Could this be a limitation or a bug in how MimePartMatcher / MimeKit handles real multipart/form-data requests?
Or is there a recommended approach to match multipart requests in JSON mappings?

Thank you in advance for your time and for maintaining this great library!

Originally created by @BrunoBeraud on GitHub (Oct 24, 2025). Originally assigned to: @StefH on GitHub. Hello, First of all, thank you for this library — it helps us a lot in our development work! I'm using **WireMock.Net.Testcontainers 1.15.0** for our tests and the **`sheyenrath/wiremock.net-alpine:1.15.0`** Docker image in our development environment. We want to define a stub endpoint that accepts a `multipart/form-data` HTTP request. Unfortunately, we’re not able to create a request body matcher using `MimePartMatcher` in a JSON mapping file. --- ### **What Works** This body matcher works correctly: ```json "Body": { "Matcher": { "Name": "RegexMatcher", "Pattern": ".+" } } ``` --- ### **What Doesn’t Work** When using `MimePartMatcher`, even with very lenient matchers, the matcher always returns a **0.0 score** for the body: ```json "Body": { "Matcher": { "Name": "MimePartMatcher", "ContentTypeMatcher": { "Name": "RegexMatcher", "Pattern": ".*" }, "ContentDispositionMatcher": { "Name": "RegexMatcher", "Pattern": ".*" }, "ContentMatcher": { "Name": "RegexMatcher", "Pattern": ".*" } } } ``` I also tried: * `WildcardMatcher` with `*` for all matchers * `JsonMatcher` with the exact JSON sent * `JsonPartialMatcher` using regex (with `"Regex": true`) and `.*` for all JSON values * Setting `"ContentTypeMatcher"` with `"Name": "ContentTypeMatcher"` and `"Pattern": "application/json"` → Always a **0.0 score** for `BodyMatcher` (while `PathMatcher`, `MethodMatcher`, and `HeadersMatcher` all score **1.0**). --- ### **Request Example** Here’s a sample `curl` request (exported from Postman): ```bash curl -L -X POST "http://localhost:8080/my-stub-endpoint" \ -F "metadata=\"{\\\"ID\\\": \\\"9858013b-e020-4ef9-b8a8-0bebc740e6a7\\\", \\\"DATE\\\": \\\"2025-08-15T13:45:30.0000000Z\\\", \\\"NAME\\\": \\\"32c9a8dd-e214-4afb-9611-9cde81f827c6\\\", \\\"NUMBER\\\": 10}\";type=application/json" ``` --- ### **Observation** From the `/__admin/requests` endpoint, here’s an example of the request body WireMock receives: ``` "Headers": { "Accept": [ "*/*" ], "Host": [ "localhost:8080" ], "User-Agent": [ "curl/8.13.0" ], "Content-Type": [ "multipart/form-data; boundary=------------------------woli8b80pw4vBJtNpAMOKS" ], "Content-Length": [ "334" ] }, "Body": "--------------------------woli8b80pw4vBJtNpAMOKS\r\n Content-Disposition: form-data; name=\"metadata\"\r\n Content-Type: application/json\r\n \r\n {\"ID\": \"9858013b-e020-4ef9-b8a8-0bebc740e6a7\", \"DATE\": \"2025-08-15T13:45:30.0000000Z\", \"NAME\": \"32c9a8dd-e214-4afb-9611-9cde81f827c6\", \"NUMBER\": 10}\r\n --------------------------woli8b80pw4vBJtNpAMOKS--\r\n" ``` After digging a bit into the code, it seems that the issue comes from the use of the **MimeKit** library, which appears unable to parse this request body. As a result, WireMock fails to extract the body parts, and the matcher score stays at its default value (`0.0`). --- ### **Possible Root Cause** It looks like the body content doesn’t include headers (such as `Content-Type` with a boundary) that would allow `MimeKit` to properly parse it into `BodyParts`. In real HTTP requests, this header is **not part of the body** — it’s in the request headers — which might explain the mismatch compared to the examples in `MimePartMatcherTests`, where the content type is included in the body. --- ### **Question** Could this be a limitation or a bug in how `MimePartMatcher` / `MimeKit` handles real multipart/form-data requests? Or is there a recommended approach to match multipart requests in JSON mappings? Thank you in advance for your time and for maintaining this great library!
adam added the question label 2025-12-29 08:32:58 +01:00
Author
Owner

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

@BrunoBeraud
I need to check.

@StefH commented on GitHub (Dec 7, 2025): @BrunoBeraud I need to check.
Author
Owner

@StefH commented on GitHub (Dec 8, 2025):

@BrunoBeraud
I did check the code and it's correct, in my unit tests I need to pass that text (including Content-Type as part of the body) to get a valid MimeMessage with 3 parts.

The real code will use the Header and prepend this to your body.


I think that your mapping json is wrong.
A possible mapping json for checking 3 parts (same as in the unit test) can be like:

{
    "Guid": "b9c82182-e469-41da-bcaf-b6e3157fefdb",
    "UpdatedAt": "2023-07-24T18:12:55.564978Z",
    "Request": {
        "Path": {
            "Matchers": [
                {
                    "Name": "WildcardMatcher",
                    "Pattern": "/multipart",
                    "IgnoreCase": false
                }
            ]
        },
        "Methods": [
            "POST"
        ],
        "Body": {
            "Matchers": [
                {
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "text/plain",
                        "IgnoreCase": false
                    },
                    "ContentMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "This is some plain text",
                        "IgnoreCase": false
                    },
                    "Name": "MimePartMatcher"
                },
                {
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "text/json",
                        "IgnoreCase": false
                    },
                    "ContentMatcher": {
                        "Name": "JsonMatcher",
                        "Pattern": {
                            "Key": "Value"
                        },
                        "IgnoreCase": true
                    },
                    "Name": "MimePartMatcher"
                },
                {
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "image/png",
                        "IgnoreCase": true
                    },
                    "ContentDispositionMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "attachment; filename=\"image.png\"",
                        "IgnoreCase": true
                    },
                    "ContentTransferEncodingMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "base64",
                        "IgnoreCase": true
                    },
                    "ContentMatcher": {
                        "Name": "ExactObjectMatcher",
                        "Pattern": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"
                    },
                    "Name": "MimePartMatcher"
                }
            ],
            "MatchOperator": "Or"
        }
    },
    "Response": {
        "BodyDestination": "SameAsSource",
        "Body": "MultiPart is ok"
    }
}

See also this extra unit test --> https://github.com/wiremock/WireMock.Net/pull/1389

@StefH commented on GitHub (Dec 8, 2025): @BrunoBeraud I did check the code and it's correct, in my unit tests I need to pass that text (including Content-Type as part of the body) to get a valid MimeMessage with 3 parts. The real code will use the Header and prepend this to your body. --- I think that your mapping json is wrong. A possible mapping json for checking 3 parts (same as in the unit test) can be like: ``` json { "Guid": "b9c82182-e469-41da-bcaf-b6e3157fefdb", "UpdatedAt": "2023-07-24T18:12:55.564978Z", "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "/multipart", "IgnoreCase": false } ] }, "Methods": [ "POST" ], "Body": { "Matchers": [ { "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "text/plain", "IgnoreCase": false }, "ContentMatcher": { "Name": "ExactMatcher", "Pattern": "This is some plain text", "IgnoreCase": false }, "Name": "MimePartMatcher" }, { "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "text/json", "IgnoreCase": false }, "ContentMatcher": { "Name": "JsonMatcher", "Pattern": { "Key": "Value" }, "IgnoreCase": true }, "Name": "MimePartMatcher" }, { "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "image/png", "IgnoreCase": true }, "ContentDispositionMatcher": { "Name": "ExactMatcher", "Pattern": "attachment; filename=\"image.png\"", "IgnoreCase": true }, "ContentTransferEncodingMatcher": { "Name": "ExactMatcher", "Pattern": "base64", "IgnoreCase": true }, "ContentMatcher": { "Name": "ExactObjectMatcher", "Pattern": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC" }, "Name": "MimePartMatcher" } ], "MatchOperator": "Or" } }, "Response": { "BodyDestination": "SameAsSource", "Body": "MultiPart is ok" } } ``` --- See also this extra unit test --> https://github.com/wiremock/WireMock.Net/pull/1389
Author
Owner

@BrunoBeraud commented on GitHub (Dec 17, 2025):

Hello, I have tried your json multipart request mapping file with sheyenrath/wiremock.net-alpine:1.15.0 docker container.
I used this curl request:
curl -X POST http://localhost:8080/multipart \ -F 'plainText=This is some plain text;type=text/plain' \ -F 'jsonData={ "Key": "Value" };type=text/json' \ -F 'image=@image.png;type=image/png'
The image is the one expecting in the ExactObjectMatcher base64 pattern

MatchDetails all 1.0 but BodyMatcher still 0.0...

@BrunoBeraud commented on GitHub (Dec 17, 2025): Hello, I have tried your json multipart request mapping file with sheyenrath/wiremock.net-alpine:1.15.0 docker container. I used this curl request: `curl -X POST http://localhost:8080/multipart \ -F 'plainText=This is some plain text;type=text/plain' \ -F 'jsonData={ "Key": "Value" };type=text/json' \ -F 'image=@image.png;type=image/png'` The image is the one expecting in the ExactObjectMatcher base64 pattern MatchDetails all 1.0 but BodyMatcher still 0.0...
Author
Owner

@StefH commented on GitHub (Dec 18, 2025):

@BrunoBeraud

I did not test the Docker image, but just local code.
And the mapping in json is like:

{
    "Guid": "b9c82182-e469-41da-bcaf-b6e3157fefdb",
    "UpdatedAt": "2025-12-18T17:21:57.3879723Z",
    "Request": {
        "Path": {
            "Matchers": [
                {
                    "Name": "WildcardMatcher",
                    "Pattern": "/multipart",
                    "IgnoreCase": false
                }
            ]
        },
        "Methods": [
            "POST"
        ],
        "Body": {
            "Matchers": [
                {
                    "Name": "MimePartMatcher",
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "text/plain",
                        "IgnoreCase": false
                    },
                    "ContentMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "This is some plain text",
                        "IgnoreCase": false
                    }
                },
                {
                    "Name": "MimePartMatcher",
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "text/json",
                        "IgnoreCase": false
                    },
                    "ContentMatcher": {
                        "Name": "JsonMatcher",
                        "Pattern": {
                            "Key": "Value"
                        },
                        "IgnoreCase": true,
                        "Regex": false
                    }
                },
                {
                    "Name": "MimePartMatcher",
                    "ContentTypeMatcher": {
                        "Name": "ContentTypeMatcher",
                        "Pattern": "image/png",
                        "IgnoreCase": false
                    },
                    "ContentDispositionMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "attachment; filename=\"image.png\"",
                        "IgnoreCase": false
                    },
                    "ContentTransferEncodingMatcher": {
                        "Name": "ExactMatcher",
                        "Pattern": "base64",
                        "IgnoreCase": false
                    },
                    "ContentMatcher": {
                        "Name": "ExactObjectMatcher",
                        "Pattern": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"
                    }
                }
            ],
            "MatchOperator": "Or"
        }
    },
    "Response": {
        "BodyDestination": "SameAsSource",
        "Body": "MultiPart is ok"
    }
}

The same mapping in code is:

var textPlainContentTypeMatcher = new ContentTypeMatcher("text/plain");
var textPlainContentMatcher = new ExactMatcher("This is some plain text");
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);

var textJsonContentTypeMatcher = new ContentTypeMatcher("text/json");
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
var textJsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);

var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png");
var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64");
var imagePngContentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher);

var matchers = new IMatcher[]
{
    textPlainMatcher,
    textJsonMatcher,
    imagePngMatcher
};

server
    .Given(Request.Create()
        .WithPath("/multipart")
        .UsingPost()
        .WithMultiPart(matchers)
    )
    .WithGuid("b9c82182-e469-41da-bcaf-b6e3157fefdb")
    .RespondWith(Response.Create()
        .WithBody("MultiPart is ok")
    );

See also:
https://github.com/wiremock/WireMock.Net/blob/mime-part-matcher/examples/WireMock.Net.Console.NET8/MainApp.cs#L559


The image.png is attached to this comment.
(It's a small red dot below...)
Image


Running CURL on windows:

PS C:\temp> curl -X POST http://localhost:9091/multipart \ -F 'plainText=This is some plain text;type=text/plain' \ -F 'jsonData={ "Key": "Value" };type=text/json' \ -F 'image=@image.png;type=image/png'
MultiPart is okcurl: (3) URL rejected: Bad hostname
curl: (3) URL rejected: Bad hostname
curl: (3) URL rejected: Bad hostname
PS C:\temp>

Logging:

18/12/2025 17:30:39 [DebugRequestResponse] : Admin[False] {
  "Guid": "950acde0-f0eb-4810-ba07-022e7305c39e",
  "Request": {
    "ClientIP": "::1",
    "DateTime": "2025-12-18T17:30:37.2241528Z",
    "Path": "/multipart",
    "AbsolutePath": "/multipart",
    "Url": "http://localhost:9091/multipart",
    "AbsoluteUrl": "http://localhost:9091/multipart",
    "ProxyUrl": null,
    "Query": {},
    "Method": "POST",
    "HttpVersion": "1.1",
    "Headers": {
      "Accept": [
        "*/*"
      ],
      "Host": [
        "localhost:9091"
      ],
      "User-Agent": [
        "curl/8.16.0"
      ],
      "Content-Type": [
        "multipart/form-data; boundary=------------------------5kocnZUaqTqJbcOKOCaG3m"
      ],
      "Content-Length": [
        "591"
      ]
    },
    "Cookies": {},
    "Body": null,
    "BodyAsJson": null,
    "BodyAsBytes": "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS01a29jblpVYXFUcUpiY09LT0NhRzNtDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9InBsYWluVGV4dCINCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbg0KDQpUaGlzIGlzIHNvbWUgcGxhaW4gdGV4dA0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS01a29jblpVYXFUcUpiY09LT0NhRzNtDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9Impzb25EYXRhIg0KQ29udGVudC1UeXBlOiB0ZXh0L2pzb24NCg0KeyAiS2V5IjogIlZhbHVlIiB9DQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTVrb2NuWlVhcVRxSmJjT0tPQ2FHM20NCkNvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0YTsgbmFtZT0iaW1hZ2UiOyBmaWxlbmFtZT0iaW1hZ2UucG5nIg0KQ29udGVudC1UeXBlOiBpbWFnZS9wbmcNCg0KiVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCCDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTVrb2NuWlVhcVRxSmJjT0tPQ2FHM20tLQ0K",
    "BodyEncoding": null,
    "DetectedBodyType": "Bytes",
    "DetectedBodyTypeFromContentType": "MultiPart"
  },
  "Response": {
    "StatusCode": null,
    "Headers": {},
    "BodyDestination": "SameAsSource",
    "Body": "MultiPart is ok",
    "BodyAsJson": null,
    "BodyAsBytes": null,
    "BodyAsFile": null,
    "BodyAsFileIsCached": null,
    "BodyOriginal": null,
    "BodyEncoding": {
      "CodePage": 65001,
      "EncodingName": "Unicode (UTF-8)",
      "WebName": "utf-8"
    },
    "DetectedBodyType": 1,
    "DetectedBodyTypeFromContentType": null,
    "FaultType": null,
    "FaultPercentage": null
  },
  "MappingGuid": "b9c82182-e469-41da-bcaf-b6e3157fefdb",
  "MappingTitle": null,
  "RequestMatchResult": {
    "TotalScore": 3.0,
    "TotalNumber": 3,
    "IsPerfectMatch": true,
    "AverageTotalScore": 1.0,
    "MatchDetails": [
      {
        "Name": "PathMatcher",
        "Score": 1.0
      },
      {
        "Name": "MethodMatcher",
        "Score": 1.0
      },
      {
        "Name": "MultiPartMatcher",
        "Score": 1.0
      }
    ]
  },
  "PartialMappingGuid": "b9c82182-e469-41da-bcaf-b6e3157fefdb",
  "PartialMappingTitle": null,
  "PartialRequestMatchResult": {
    "TotalScore": 3.0,
    "TotalNumber": 3,
    "IsPerfectMatch": true,
    "AverageTotalScore": 1.0,
    "MatchDetails": [
      {
        "Name": "PathMatcher",
        "Score": 1.0
      },
      {
        "Name": "MethodMatcher",
        "Score": 1.0
      },
      {
        "Name": "MultiPartMatcher",
        "Score": 1.0
      }
    ]
  }
}

@StefH commented on GitHub (Dec 18, 2025): @BrunoBeraud I did not test the Docker image, but just local code. And the mapping in json is like: ``` json { "Guid": "b9c82182-e469-41da-bcaf-b6e3157fefdb", "UpdatedAt": "2025-12-18T17:21:57.3879723Z", "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "/multipart", "IgnoreCase": false } ] }, "Methods": [ "POST" ], "Body": { "Matchers": [ { "Name": "MimePartMatcher", "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "text/plain", "IgnoreCase": false }, "ContentMatcher": { "Name": "ExactMatcher", "Pattern": "This is some plain text", "IgnoreCase": false } }, { "Name": "MimePartMatcher", "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "text/json", "IgnoreCase": false }, "ContentMatcher": { "Name": "JsonMatcher", "Pattern": { "Key": "Value" }, "IgnoreCase": true, "Regex": false } }, { "Name": "MimePartMatcher", "ContentTypeMatcher": { "Name": "ContentTypeMatcher", "Pattern": "image/png", "IgnoreCase": false }, "ContentDispositionMatcher": { "Name": "ExactMatcher", "Pattern": "attachment; filename=\"image.png\"", "IgnoreCase": false }, "ContentTransferEncodingMatcher": { "Name": "ExactMatcher", "Pattern": "base64", "IgnoreCase": false }, "ContentMatcher": { "Name": "ExactObjectMatcher", "Pattern": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC" } } ], "MatchOperator": "Or" } }, "Response": { "BodyDestination": "SameAsSource", "Body": "MultiPart is ok" } } ``` The same mapping in code is: ``` c# var textPlainContentTypeMatcher = new ContentTypeMatcher("text/plain"); var textPlainContentMatcher = new ExactMatcher("This is some plain text"); var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher); var textJsonContentTypeMatcher = new ContentTypeMatcher("text/json"); var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true); var textJsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher); var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png"); var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\""); var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64"); var imagePngContentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC")); var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher); var matchers = new IMatcher[] { textPlainMatcher, textJsonMatcher, imagePngMatcher }; server .Given(Request.Create() .WithPath("/multipart") .UsingPost() .WithMultiPart(matchers) ) .WithGuid("b9c82182-e469-41da-bcaf-b6e3157fefdb") .RespondWith(Response.Create() .WithBody("MultiPart is ok") ); ``` See also: https://github.com/wiremock/WireMock.Net/blob/mime-part-matcher/examples/WireMock.Net.Console.NET8/MainApp.cs#L559 --- The image.png is attached to this comment. (It's a small red dot below...) <img width="2" height="2" alt="Image" src="https://github.com/user-attachments/assets/5f742196-0d39-4180-9a58-7b2aa4721552" /> --- Running CURL on windows: ``` cmd PS C:\temp> curl -X POST http://localhost:9091/multipart \ -F 'plainText=This is some plain text;type=text/plain' \ -F 'jsonData={ "Key": "Value" };type=text/json' \ -F 'image=@image.png;type=image/png' MultiPart is okcurl: (3) URL rejected: Bad hostname curl: (3) URL rejected: Bad hostname curl: (3) URL rejected: Bad hostname PS C:\temp> ``` --- Logging: ``` 18/12/2025 17:30:39 [DebugRequestResponse] : Admin[False] { "Guid": "950acde0-f0eb-4810-ba07-022e7305c39e", "Request": { "ClientIP": "::1", "DateTime": "2025-12-18T17:30:37.2241528Z", "Path": "/multipart", "AbsolutePath": "/multipart", "Url": "http://localhost:9091/multipart", "AbsoluteUrl": "http://localhost:9091/multipart", "ProxyUrl": null, "Query": {}, "Method": "POST", "HttpVersion": "1.1", "Headers": { "Accept": [ "*/*" ], "Host": [ "localhost:9091" ], "User-Agent": [ "curl/8.16.0" ], "Content-Type": [ "multipart/form-data; boundary=------------------------5kocnZUaqTqJbcOKOCaG3m" ], "Content-Length": [ "591" ] }, "Cookies": {}, "Body": null, "BodyAsJson": null, "BodyAsBytes": "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS01a29jblpVYXFUcUpiY09LT0NhRzNtDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9InBsYWluVGV4dCINCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbg0KDQpUaGlzIGlzIHNvbWUgcGxhaW4gdGV4dA0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS01a29jblpVYXFUcUpiY09LT0NhRzNtDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9Impzb25EYXRhIg0KQ29udGVudC1UeXBlOiB0ZXh0L2pzb24NCg0KeyAiS2V5IjogIlZhbHVlIiB9DQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTVrb2NuWlVhcVRxSmJjT0tPQ2FHM20NCkNvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0YTsgbmFtZT0iaW1hZ2UiOyBmaWxlbmFtZT0iaW1hZ2UucG5nIg0KQ29udGVudC1UeXBlOiBpbWFnZS9wbmcNCg0KiVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCCDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTVrb2NuWlVhcVRxSmJjT0tPQ2FHM20tLQ0K", "BodyEncoding": null, "DetectedBodyType": "Bytes", "DetectedBodyTypeFromContentType": "MultiPart" }, "Response": { "StatusCode": null, "Headers": {}, "BodyDestination": "SameAsSource", "Body": "MultiPart is ok", "BodyAsJson": null, "BodyAsBytes": null, "BodyAsFile": null, "BodyAsFileIsCached": null, "BodyOriginal": null, "BodyEncoding": { "CodePage": 65001, "EncodingName": "Unicode (UTF-8)", "WebName": "utf-8" }, "DetectedBodyType": 1, "DetectedBodyTypeFromContentType": null, "FaultType": null, "FaultPercentage": null }, "MappingGuid": "b9c82182-e469-41da-bcaf-b6e3157fefdb", "MappingTitle": null, "RequestMatchResult": { "TotalScore": 3.0, "TotalNumber": 3, "IsPerfectMatch": true, "AverageTotalScore": 1.0, "MatchDetails": [ { "Name": "PathMatcher", "Score": 1.0 }, { "Name": "MethodMatcher", "Score": 1.0 }, { "Name": "MultiPartMatcher", "Score": 1.0 } ] }, "PartialMappingGuid": "b9c82182-e469-41da-bcaf-b6e3157fefdb", "PartialMappingTitle": null, "PartialRequestMatchResult": { "TotalScore": 3.0, "TotalNumber": 3, "IsPerfectMatch": true, "AverageTotalScore": 1.0, "MatchDetails": [ { "Name": "PathMatcher", "Score": 1.0 }, { "Name": "MethodMatcher", "Score": 1.0 }, { "Name": "MultiPartMatcher", "Score": 1.0 } ] } } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net#721