Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

API controller POST method multipart/form-data using boundary get message inside the body

I'm having trouble developing a C# (.Net 5) method on an API controller who can manage request who have 'multipart/form-data; boundary=boundary'

I can't change the request on the client side, I only can modify my backend to adapt to it.

The request specify the 'Content-Type: multipart/form-data; boundary=boundary', and it has a json message inside the body that I need to extract.

Inside the body of the request the message is like this:

--boundary
Content-Disposition: form-data; name="ZZZZZZZZZZ"
Content-Type: application/json
Content-Length: 474

{
    //a well formed json
}
--boundary--

I can get that using this code: string dataMessage = new StreamReader(Request.Body).ReadToEndAsync().Result;

Then I can manually parse that string to extract only the json part using IndexOf and Substring, and then cast it to an object using JsonConvert.

I'm wondering if there is some option on .Net to do this automatically without the manual parsing of the string. I think that there must be some way to interpret the boundary token and get the json data directly. But i can't found any :( That came to my mind because when using webhook.site to test the client request, it can parse the message without any problems.

My controller definition is like this

[ApiController]
[Route("api/[controller]")]
public class XXXXController : ControllerBase

And the method is like this

[HttpPost]
[Route("[action]")]
public IActionResult YYYYYYY()

I already tried to specify the model binding to change the behaviour but I can't get it working.

And I already search help before asking:

  • https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0#model-binding-for-http-get-requests
  • https://forums.asp.net/t/2162362.aspx?Read+POST+data+in+request+body
  • How to get POST data in WebAPI?
  • how to read multi part form data in .net web api controller
  • ASP.NET MVC. How to create Action method that accepts and multipart/form-data
  • 415 Unsupported Media Type when uploading "multipart/form-data" to .Net Core 3.1 API but the file is accessible in middleware method
  • ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type response
  • ASP.NET How read a multipart form data in Web API?
  • How to send multipart/form-data to ASP.NET Core Web API?
  • How to set up a Web API controller for multipart/form-data
  • Send POST request through WebClient with boundary
  • Web API Simplest way to pickup a multipart/form-data response
  • How to get Json Post Values with asp.net webapi
  • What is the boundary in multipart/form-data?
  • C# HTTP POST with Boundary
  • How to set MIME type for POST - multipart/form-data in axios?

Thanks for your help!!

like image 525
Johna Avatar asked Sep 16 '25 01:09

Johna


1 Answers

There isn't built-in support of multi-part/form-data Media Type in .Net5 by default. So, the input formatter should be attached to the MvcBuilder.

Considering the fact that you can't manipulate client-side, ApiMultipartFormDataFormatter which enables this type of input formatting can be utilized.

  1. Add the Package:

Install-Package ApiMultipartFormDataFormatter -Version 3.0.0

  1. Configure the Formatter in Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(options =>
        {
            options.InputFormatters.Add(new MultipartFormDataFormatter());
        });
    }
    
  2. Assuming the mentioned well formed json is something like below class:

    public class CustomContent
    {
        public string Name { get; set; }
    }
    

    So, we need to wrap it up into another class that contains this as a parameter. Note: The library doesn't support deserialization by this moment So, a getter-only property is added to the model which returns the deserialized object.

    public class ViewModel
    {
        // Equivalent to ZZZZZZZZZZ
        public string SerializedContent { get; set; }
        public CustomContent Content => !string.IsNullOrEmpty(SerializedContent)
            ? JsonConvert.DeserializeObject<CustomContent>(SerializedContent)
            : null;
    }
    
  3. Reform the Action to accept the wrapper model.

    [HttpPost]
    [Route("[action]")]
    public IActionResult Parse(ViewModel vm)
    {            
        return Ok($"Received Name: {vm?.Content?.Name}");
    }
    

The working cURL request of the corresponding example is:

curl --location --request POST 'http://localhost:25599/api/MultiPart/Parse' 

\
--header 'Content-Type: multipart/form-data; boundary=boundary' \
--data-raw '--boundary
Content-Disposition: form-data; name="SerializedContent"
Content-Type: application/json
Content-Length: 100

{
    "Name" : "Foo"
}
--boundary--'

The response should be equal to Received Name: Foo.

like image 121
A.Mokhtari Avatar answered Sep 17 '25 14:09

A.Mokhtari