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

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

我在可以管理具有 'multipart/form-data; boundary=boundary'

请求的 API 控制器上开发 C# (.Net 5) 方法时遇到问题

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

请求指定了 'Content-Type: multipart/form-data; boundary=boundary',正文中有一条 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()

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

而且我在提问之前已经搜索了帮助:

感谢您的帮助!!

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

考虑到您无法在客户端进行操作,ApiMultipartFormDataFormatter 可以使用启用此类输入格式的功能。

  1. 添加包:

Install-Package ApiMultipartFormDataFormatter -Version 3.0.0

  1. Startup.cs

    中配置格式化程序
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(options =>
        {
            options.InputFormatters.Add(new MultipartFormDataFormatter());
        });
    }
    
  2. 假设上述格式正确的 json 如下所示 class:

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

    因此,我们需要将其包装到另一个包含此参数的 class 中。 注意: 库目前不支持反序列化因此,getter-only 属性 添加到 returns 反序列化的模型中对象。

    public class ViewModel
    {
        // Equivalent to ZZZZZZZZZZ
        public string SerializedContent { get; set; }
        public CustomContent Content => !string.IsNullOrEmpty(SerializedContent)
            ? JsonConvert.DeserializeObject<CustomContent>(SerializedContent)
            : null;
    }
    
  3. 改造 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