简体   繁体   English

ASP.NET Core Web API - Get file along with [FromBody] JSON model

[英]ASP.NET Core Web API - Get file along with [FromBody] JSON model

I have an existing API endpoint that receives data from a the client.我有一个现有的 API 端点,它从客户端接收数据。 I want to add the ability to receive files on that endpoint along with the data.我想添加在该端点上接收文件以及数据的功能。 This is my model:这是我的 model:

public class TestModel
{
    public IList<IFormFile> File { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Hobbies { get; set; }
}

And this is my endpoint:这是我的终点:

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

I'm currently testing my API with Postman.我目前正在用 Postman 测试我的 API。 I know that in Postman there is an option to send files with form-data as the body, but in such case my client would need to use form-data and I with to use json as data (using FromBody ).我知道在 Postman 中有一个选项可以发送带有form-data文件,但在这种情况下,我的客户需要使用form-data ,而我使用 json 作为数据(使用FromBody )。

I can't find a way how to do that - is it possible?我找不到如何做到这一点的方法 - 有可能吗? And if so, how do I use Postman to send the file view raw json?如果是这样,我如何使用 Postman 发送文件视图raw json?

When uploading files, if you choose to use JSON, then you are putting the client in a pickle.上传文件时,如果您选择使用 JSON,那么您将客户端置于泡菜中。 You are going to force the client to have to Base64-encode all files.您将强制客户端必须对所有文件进行 Base64 编码。 This can be a cumbersome task for clients to do especially if it's browser JS code.对于客户端来说,这可能是一项繁琐的任务,特别是如果它是浏览器 JS 代码。 Not to mention you increase your payload 33%.更不用说你增加了 33% 的有效载荷。

Form-Data?表单数据?

When posting files, you want to use HTML forms.发布文件时,您要使用 HTML forms。 This is something a browser is very good at.这是浏览器非常擅长的事情。

With that being said, the proper way to do this would be to set up your endpoint to look like this:话虽如此,正确的方法是将端点设置为如下所示:

// 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();
}

Take note of the [FromForm] parameter.记下[FromForm]参数。

Then set up postman to look like this:然后设置 postman 看起来像这样:

邮差

  1. Set it to Post .将其设置为Post
  2. Go to the Body section and set it to Form-Data . Go 到Body部分并将其设置为Form-Data
  3. Add in the parameters.添加参数。 You can test multiple files by adding the same parameter name multiple times.您可以通过多次添加相同的参数名称来测试多个文件。
  4. Click Send .单击Send

When the endpoint gets hit, it should look like this:当端点被命中时,它应该如下所示:

发布数据

JSON? JSON?

Let's say you absolutely must use JSON as the post data.假设您绝对必须使用 JSON 作为发布数据。 Then your model will look like this:然后您的 model 将如下所示:

public class TestModel
{
    public IList<byte[]> File { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Hobbies { get; set; }
}

You would change your endpoint from [FromForm] to [FromBody] , then you will have to convince your front-end devs they must encode all files with Base64 and build a JSON object to send.您将端点从[FromForm]更改为[FromBody] ,然后您必须说服前端开发人员他们必须使用Base64对所有文件进行编码并构建 JSON ZA8CFDE6331BD59EB2AC96F8911C4B66 到 send。 I don't think you will be super successful with that as it's not optimized nor is it the norm.我认为您不会因此而获得超级成功,因为它没有经过优化,也不是常态。 They may give you strange looks.他们可能会给你奇怪的表情。

Let's run through the scenario:让我们来看看这个场景:

  1. User selects 3 files.用户选择 3 个文件。 Each are 100 MB a piece.每个都是 100 MB。
  2. User clicks "submit" and JS now reads 300 MB in to memory.用户单击“提交”,JS 现在将 300 MB 读入 memory。
  3. JS encodes 300 MB of files to Base64 in the browser. JS 在浏览器中将 300 MB 的文件编码为 Base64。 Memory usage has increased to 400 MB. Memory 使用量已增加到 400 MB。
  4. JS client builds the JSON payload -- Memory increases again as a new string needs to be created based on the 400 MB of strings. JS 客户端构建 JSON 有效负载 - Memory 再次增加,因为需要基于 400 MB 字符串创建新字符串。
  5. Network traffic starts.网络流量开始。
  6. Backend gets the post data.后端获取帖子数据。 Since it's JSON, ASP.NET Core will deserialize to your model.由于它是 JSON,因此 ASP.NET 内核将反序列化为您的 model。 The framework will have to allocate 400 MB of memory to read in the JSON from the network.框架必须分配 400 MB 的 memory 以从网络读取 JSON。
  7. ASP.NET will deserialize, which also requires the decoding of 400 MB of data, which isn't a light task. ASP.NET 将反序列化,这也需要解码 400 MB 的数据,这不是一项轻松的任务。
  8. Your endpoint gets invoked with a ~300MB model in memory .您的端点在 memory 中使用 ~300MB model 调用。

You will run in to OutOfMemory exceptions at some point.您将在某个时候遇到 OutOfMemory 异常。 It's almost guaranteed.几乎可以保证。

Form data is extremely optimized in ASP.NET Core.表格数据在 ASP.NET 内核中得到了极大的优化。 It will use memory for smaller files, but then dump to disk for larger files.它将使用 memory 处理较小的文件,然后转储到磁盘以获取较大的文件。 It's impossible to run in to memory issues when using Form data.使用表单数据时不可能遇到 memory 问题。

Let's run though a Form scenario:让我们运行一个表单场景:

  1. User selects 3 files.用户选择 3 个文件。 Each are 100 MB a piece.每个都是 100 MB。
  2. User clicks "submit".用户点击“提交”。 Browser will now start a request to the back-end and reads in the file to small chunks of memory and send it up chunk-by-chunk.浏览器现在将向后端发起请求,并将文件读入 memory 的小块并逐块发送。 One file at a time.一次一个文件。 The size of these chunks are optimized based on environment.这些块的大小根据环境进行了优化。 Will not exceed what is necessary to transfer the data efficiently.不会超过有效传输数据所需的量。 Memory usage will be minimal. Memory 的使用量将最少。
  3. ASP.NET starts reading the data. ASP.NET 开始读取数据。 If the IFormFile data exceed 5 MB (I believe that's the limit), it will move it from an in-memory stream to a disk stream.如果IFormFile数据超过 5 MB(我相信这是限制),它会将其从内存 stream 移动到磁盘 stream。
  4. ASP.NET invokes your endpoint with references to streams that originate from the disk. ASP.NET 使用对源自磁盘的流的引用来调用您的端点。 The size of your model in memory is irrelevant since it's just holding references to disk streams. memory 中 model 的大小无关紧要,因为它只是保存对磁盘流的引用。

PostMan? PostMan? There isn't a way to do this in PostMan without scripting something, again because it's not normal to do.在 PostMan 中没有任何方法可以在不编写脚本的情况下执行此操作,同样因为这不正常。 I'm sure if you google the subject you may find something, but it will be kludgy at best.我敢肯定,如果你用谷歌搜索这个主题,你可能会找到一些东西,但充其量只是很笨拙。

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; }
    }
}

Here is what the request should look like from postman.这是来自 postman 的请求的样子。

在此处输入图像描述

Here is proof the we got the file.这是我们得到文件的证据。 在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在asp.net核心中调用asp.net mvc 5 Web api,FromBody始终为null - calling asp.net mvc 5 web api in asp.net core, FromBody always null ASP.NET 内核上传多个文件 Web API Z20F35E630DAF44DBFA4C3F68F5399D8 - ASP.NET Core Upload Multiple File Web API model 在 ASP.Net Core 5 MVC 控制器中,当传递包含小数的 JSON 对象 FromBody 时,模型始终为空 - In ASP.Net Core 5 MVC Controller, when passed a JSON object FromBody that contains a decimal the model is always null 在ASP.NET CORE中将属性路由值转换为Model / FromBody参数 - Attribute Routing Values into Model/FromBody Parameter in ASP.NET CORE 如何让ASP.NET Core 2.0 MVC Model Binder绑定没有FromBody属性的复杂类型 - How to get the ASP.NET Core 2.0 MVC Model Binder to bind complex types without FromBody attributes FromBody 在 ASP.NET 核心 API 返回 null - FromBody in ASP.NET Core API returns null 将整齐格式的json数据发送到asp.net Web API,而不是默认的[FromBody]行为 - send neatly formatted json data to asp.net web api instead of default [FromBody] behavior 与 ASP.NET Core 中的 FromBody 混淆 - Confused with FromBody in ASP.NET Core ASP.NET 核心 - [FromBody] 的奇怪行为 - ASP.NET Core - weird behavior with [FromBody] ASP.NET Core Web API 模型绑定行为更改 - ASP.NET Core Web API Model binding behavior change
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM