如何编写接受文件的 API 操作方法?

How to write API action method that would accept a file?

我正在尝试编写一个 API 端点,允许用户使用 Asp.NET Core 3.1 将文件发送到我的服务器。

我有以下操作方法需要响应客户端的请求并处理文件验证并存储文件。

[HttpPost, Route("api/store")]
public async Task<IActionResult> Store([FromBody] MultipartFormDataContent content)
{
    // Validate the file, store it.

    return Ok();
}

我正在尝试像这样从客户端发送文件

using HttpClient client = new HttpClient();

var multiForm = new MultipartFormDataContent();
multiForm.Add(new StringContent("1/12/1.jpg"), "custom_file_name");
FileStream fs = System.IO.File.OpenRead("1.jpg");
multiForm.Add(new StreamContent(fs), "file", "1.jpg");

// send request to API
var url = "https://localhost:123/api/store";
var response = await client.PostAsync(url, multiForm);

但是服务器returnsHTTP Code 404 Not Found.

如何正确调整上面的 Store 方法,使其接受客户端发送的文件?

您不应在操作方法路由中包含 api/。控制器的路由已经带有 api 前缀。此外,api/[controller] 表示控制器路由将是 api/ControllerName,那么您的操作将是 api/ControllerName/store

如果你的控制器 class 被命名为 ThingsController 那么它的路线是 api/things,你的 Store 动作应该是 api/things/store.

您不需要对一个动作同时使用 HttpPostRoute 属性。 Route 属性接受所有 HTTP 动词,因此使用一个或另一个(通常只是 HttpPost 或您将使用操作方法处理的任何 HTTP 动词。因此:

[ApiController]
[Route("api/[controller]")]
public class ThingsController : ControllerBase
{
    // POST api/things/store
    [HttpPost("store")]
    public async Task<IActionResult> Store([FromBody] MultipartFormDataContent content)
    {
        // Do stuff
    }
}

此外,控制器应该使用 IFormFile 来处理控制器中的文件上传。文档在这里:

Upload files in ASP.NET Core .

您的控制器将接受 IFormFile files 参数而不是 MultipartFormDataContent content

来自 MSDN 的示例,根据您的操作进行了调整

[HttpPost("store")]
public async Task<IActionResult> Store(List<IFormFile> files)
{
    // Get total size
    long size = files.Sum(f => f.Length);

    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            // Gets a temporary file name
            var filePath = Path.GetTempFileName();

            // Creates the file at filePath and copies the contents
            using (var stream = System.IO.File.Create(filePath))
            {
                await formFile.CopyToAsync(stream);
            }
        }
    }

    // Process uploaded files
    // Don't rely on or trust the FileName property without validation.

    return Ok(new { count = files.Count, size, filePath });
}

如果您正在处理单个文件,您可以只传递 IFormFile file 而不是列表,并摆脱 action 方法中的循环。

没有自己测试过这段代码,是在移动设备上编写的。希望它能解决问题。