API 控制器 POST 方法 multipart/form-data 在主体内使用边界获取消息

Posted

技术标签:

【中文标题】API 控制器 POST 方法 multipart/form-data 在主体内使用边界获取消息【英文标题】:API controller POST method multipart/form-data using boundary get message inside the body 【发布时间】:2021-10-20 08:31:45 【问题描述】:

我无法在 API 控制器上开发 C# (.Net 5) 方法,该控制器可以管理具有“multipart/form-data;”的请求;边界=边界'

我无法在客户端更改请求,我只能修改我的后端以适应它。

请求指定'Content-Type: multipart/form-data;边界=边界',它在正文中有一条我需要提取的 json 消息。

在请求的正文中,消息是这样的:

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


    //a well formed json

--boundary--

我可以使用以下代码:string dataMessage = new StreamReader(Request.Body).ReadToEndAsync().Result;

然后我可以手动解析该字符串以使用 IndexOf 和 Substring 仅提取 json 部分,然后使用 JsonConvert 将其转换为对象。

我想知道 .Net 上是否有一些选项可以在不手动解析字符串的情况下自动执行此操作。我认为必须有某种方法来解释边界标记并获取直接json数据。但我找不到任何 :( 这让我想到了,因为当使用 webhook.site 测试客户端请求时,它可以毫无问题地解析消息。

我的控制器定义是这样的

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

而且方法是这样的

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

我已经尝试指定模型绑定来更改行为,但我无法让它工作。

在提问之前我已经搜索过帮助:

https://docs.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?

感谢您的帮助!!

【问题讨论】:

【参考方案1】:

.Net5 默认不支持multi-part/form-data 媒体类型。因此,输入格式化程序应该附加到MvcBuilder

考虑到您无法操作客户端这一事实,可以使用启用此类输入格式的ApiMultipartFormDataFormatter

    添加包:

Install-Package ApiMultipartFormDataFormatter -Version 3.0.0

    Startup.cs中配置格式化程序

    public void ConfigureServices(IServiceCollection services)
    
        services.AddControllers(options =>
        
            options.InputFormatters.Add(new MultipartFormDataFormatter());
        );
    
    

    假设上述格式良好的 json 类似于下面的类:

    public class CustomContent
    
        public string Name  get; set; 
    
    

    因此,我们需要将它包装到另一个包含 this 作为参数的类中。 注意: 目前该库不支持反序列化因此,模型中添加了一个 getter-only 属性,该属性返回反序列化的对象。

    public class ViewModel
    
        // Equivalent to ZZZZZZZZZZ
        public string SerializedContent  get; set; 
        public CustomContent Content => !string.IsNullOrEmpty(SerializedContent)
            ? JsonConvert.DeserializeObject<CustomContent>(SerializedContent)
            : null;
    
    

    改革 Action 以接受包装模型。

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

对应示例的工作cURL请求为:

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--'

响应应该等于Received Name: Foo

【讨论】:

A.Mokhtari 你的回答太棒了,非常感谢。我正在更改代码,使其符合您的指示,我将对其进行测试:) 希望对您有所帮助。还有一个更好但耗时的解决方案,通过将 IModelBinderService 的新实现添加到 ApiMultipartFormDataFormatter 以启用直接反序列化来消除额外的包装器。

以上是关于API 控制器 POST 方法 multipart/form-data 在主体内使用边界获取消息的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 在 POST 方法中从 multipart/form-data 获取请求

使用 TestRestTemplate 进行 Multipart POST 请求的集成测试返回 400

文件上传 API:Multipart/form-data 与正文中的原始内容?

使用 RestSharp 在 multipart/form-data POST 中包含文件时遇到问题

使用 RestSharp 发送 HTTP POST Multipart/form-data 字段

vue-resource发送multipart/form-data数据