ASP.NET Core Web API - 获取文件以及 [FromBody] JSON 模型

dev*_*r82 5 c# asp.net asp.net-web-api asp.net-core

我有一个现有的 API 端点,可以从客户端接收数据。我想添加在该端点上接收文件和数据的功能。这是我的模型:

public class TestModel
{
    public IList<IFormFile> File { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Hobbies { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我的终点:

[HttpPost]
[Route("upload")]
public async Task<ActionResult> UploadTest([FromBody] TestModel test)
{
    return Ok();
}
Run Code Online (Sandbox Code Playgroud)

我目前正在使用 Postman 测试我的 API。我知道在 Postman 中,有一个选项可以发送文件作为form-data正文,但在这种情况下,我的客户需要使用form-datajson 作为数据(使用FromBody)。

我找不到办法做到这一点 - 有可能吗?如果是这样,我如何使用 Postman 发送文件视图rawjson?

And*_*ndy 11

上传文件时,如果您选择使用 JSON,那么您将使客户端陷入困境。您将强制客户端对所有文件进行 Base64 编码。对于客户端来说,这可能是一项繁琐的任务,特别是如果它是浏览器 JS 代码。更不用说您将有效负载增加了 33%。

表单数据?

发布文件时,您希望使用 HTML 表单。这是浏览器非常擅长的事情。

话虽如此,执行此操作的正确方法是将端点设置为如下所示:

// NOTE: This is the same as you have it in your question
public class TestModel
{
    public IList<IFormFile> File { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Hobbies { get; set; }
}

[HttpPost, Route("testme")]
public IActionResult TestMe([FromForm] TestModel testModel)
{
    return Ok();
}
Run Code Online (Sandbox Code Playgroud)

记下该[FromForm]参数。

然后将邮递员设置为如下所示:

邮差

  1. 将其设置为Post.
  2. 转到该Body部分并将其设置为Form-Data
  3. 添加参数。您可以通过多次添加相同的参数名称来测试多个文件。
  4. 点击Send

当端点被击中时,它应该如下所示:

发布数据

JSON?

假设您绝对必须使用 JSON 作为发布数据。那么你的模型将如下所示:

public class TestModel
{
    public IList<byte[]> File { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Hobbies { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您可以将端点从 更改[FromForm][FromBody],然后您必须说服前端开发人员必须使用它们对所有文件进行编码Base64并构建要发送的 JSON 对象。我不认为你会在这方面取得超级成功,因为它没有优化,也不是常态。他们可能会给你奇怪的表情。

让我们看一下这个场景:

  1. 用户选择 3 个文件。每块都是 100 MB。
  2. 用户单击“提交”,JS 现在将 300 MB 读取到内存中。
  3. JS 在浏览器中将 300 MB 的文件编码为 Base64。内存使用量已增加至 400 MB。
  4. JS 客户端构建 JSON 有效负载 - 由于需要基于 400 MB 字符串创建新字符串,因此内存再次增加。
  5. 网络流量开始。
  6. 后端获取post数据。由于它是 JSON,ASP.NET Core 将反序列化为您的模型。该框架必须分配 400 MB 内存才能从网络读取 JSON。
  7. ASP.NET 将进行反序列化,这还需要解码 400 MB 的数据,这不是一项轻松的任务。
  8. 您的端点被调用时内存中有大约 300MB 的模型。

您有时会遇到 OutOfMemory 异常。几乎可以保证。

表单数据在 ASP.NET Core 中得到了极大的优化。它将使用内存来存储较小的文件,然后将其转储到磁盘以存储较大的文件。使用表单数据时不可能遇到内存问题。

让我们运行一个表单场景:

  1. 用户选择 3 个文件。每块都是 100 MB。
  2. 用户点击“提交”。浏览器现在将向后端发起请求,并将文件读取到小块内存中,然后将其逐块发送。一次一个文件。这些块的大小根据环境进行优化。不会超出有效传输数据所需的范围。内存使用量将是最小的。
  3. ASP.NET 开始读取数据。如果IFormFile数据超过 5 MB(我相信这是限制),它会将其从内存流移动到磁盘流。
  4. ASP.NET 通过对源自磁盘的流的引用来调用端点。内存中模型的大小无关紧要,因为它只是保存对磁盘流的引用。

邮差?在 PostMan 中,没有办法在不编写脚本的情况下执行此操作,同样,因为这是不正常的做法。我确信如果你用谷歌搜索这个主题你可能会找到一些东西,但充其量也只是混乱的。


Olu*_*nwa 0

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Test.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class TestController : ControllerBase
    {
        [HttpPost]
        [Route("upload")]
        public async Task<ActionResult> UploadTest([FromForm] TestModel test)
        {
            return Ok();
        }
    }
    public class TestModel
    {
        public IList<IFormFile> File { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Hobbies { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是邮递员发出的请求。

在此输入图像描述

这是我们收到文件的证据。 在此输入图像描述