如何在 ASP.NET Core 中将没有文件名的 multipart/form-data 文件绑定到 IFormFile

Vic*_*tor 5 c# .net-core asp.net-core asp.net-core-webapi

在 ASP.NET Core 3.1 中接受 multipart/form-data 参数的简单控制器操作中:

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication
{
    public class Controller : ControllerBase
    {
        [HttpPost("length")]
        public IActionResult Post([FromForm] Input input)
        {
            if (!ModelState.IsValid)
                return new BadRequestObjectResult(ModelState);
            
            return Ok(input.File.Length);
        }
        
        public class Input
        {
            [Required]
            public IFormFile File { get; set; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我发送带有没有文件名的文件的 multipart/form-data 时(在RFC 7578下是可以接受的),它不会被识别为IFormFile. 例如:

using System;
using System.IO;
using System.Threading.Tasks;
using System.Net.Http;

namespace ConsoleApp4
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await Test(withFilename: true);
            await Test(withFilename: false);
        }

        static async Task Test(bool withFilename)
        {
            HttpClient client = new HttpClient();
            
            var fileContent = new StreamContent(new FileStream("/Users/cucho/Desktop/36KB.pdf", FileMode.Open, FileAccess.Read));
            
            var message = new HttpRequestMessage(
                HttpMethod.Post,
                "http://localhost:5000/length"
            );
            
            var content = new MultipartFormDataContent();

            if (withFilename)
            {
                content.Add(fileContent, "File", "36KB.pdf");
            }
            else
            {
                content.Add(fileContent, "File");
            }
            
            message.Content = content;
            
            var response1 = await client.SendAsync(message);

            var withString = withFilename ? "With" : "Without";
            
            Console.WriteLine($"{withString} filename: {(int)response1.StatusCode}");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果是:

With filename: 200
Without filename: 400
Run Code Online (Sandbox Code Playgroud)

如何将该没有文件名的文件绑定到 IFormFile 对象?

编辑:

我在ContentDispositionHeaderValueIdentityExtensions中找到了以下方法:

public static class ContentDispositionHeaderValueIdentityExtensions
{
    /// <summary>
    /// Checks if the content disposition header is a file disposition
    /// </summary>
    /// <param name="header">The header to check</param>
    /// <returns>True if the header is file disposition, false otherwise</returns>
    public static bool IsFileDisposition(this ContentDispositionHeaderValue header)
    {
        if (header == null)
        {
            throw new ArgumentNullException(nameof(header));
        }

        return header.DispositionType.Equals("form-data")
            && (!StringSegment.IsNullOrEmpty(header.FileName) || !StringSegment.IsNullOrEmpty(header.FileNameStar));
    }
Run Code Online (Sandbox Code Playgroud)

FormFeature中也有类似的代码,我认为这就是它如何决定该部分是否是文件的方式。

Gha*_*san 0

只是迭代 @Tieson T. 在评论中提到的内容,模型绑定程序要求文件具有文件名,无论其值如何。

我正在使用 HttpClient 发送请求,并且这有效。如果我省略文件名,它将不起作用。

var formContent = new MultipartFormDataContent();
var streamContent = new StreamContent(request.Stream);
formContent.Add(streamContent, "Photo", "any filename is accepted");
Run Code Online (Sandbox Code Playgroud)

https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ModelBinding/Binders/FormFileModelBinder.cs#L142