如何使用HttpClient发送包含IFormFile的表单数据?

27

我有一个后端终点Task<ActionResult> Post(IFormFile csvFile),我需要从HttpClient调用这个终点。目前我遇到了不支持的媒体类型错误。 下面是我的代码:

var filePath = Path.Combine("IntegrationTests", "file.csv");
var gg = File.ReadAllBytes(filePath);
var byteArrayContent = new ByteArrayContent(gg);
var postResponse = await _client.PostAsync("offers", new MultipartFormDataContent
{
    {byteArrayContent }
});

1
尝试使用另一个StackOverflow问题的此解决方案 - MindSwipe
谢谢,但它仍然显示相同的错误。 - Deivydas Voroneckis
6个回答

30
您需要在MultipartFormDataContent集合中指定与操作参数名称(csvFile)匹配的参数名称和一个随机文件名。
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(byteArrayContent, "csvFile", "filename");
var postResponse = await _client.PostAsync("offers", multipartContent);

或同等

var postResponse = await _client.PostAsync("offers", new MultipartFormDataContent {
    { byteArrayContent, "csvFile", "filename" }
});

1
谢谢,我之前缺少了这个头: content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "csvFile", FileName = fileName }; content.Headers.Remove("Content-Type"); content.Headers.Add("Content-Type", "application/octet-stream; boundary=----WebKitFormBoundaryMRxYYlVt8KWT8TU3"); - Deivydas Voroneckis
2
如果我的类型不是 IFormFile,而是 List<IFormFile> 呢?谢谢。 - Sasuke Uchiha

12
使用此代码片段:
const string url = "https://localhost:5001/api/Upload";
const string filePath = @"C:\Path\To\File.png";

using (var httpClient = new HttpClient())
{
    using (var form = new MultipartFormDataContent())
    {
        using (var fs = File.OpenRead(filePath))
        {
            using (var streamContent = new StreamContent(fs))
            {
                using (var fileContent = new ByteArrayContent(await streamContent.ReadAsByteArrayAsync()))
                {
                    fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

                    // "file" parameter name should be the same as the server side input parameter name
                    form.Add(fileContent, "file", Path.GetFileName(filePath));
                    HttpResponseMessage response = await httpClient.PostAsync(url, form);
                }
            }
        }
    }
}

我在fileContent.Headers.ContentType中缺少了MediaTypeHeaderValue,而fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");拯救了我的生命。 - eddyP23
2
你的using语句中有3/5可以简化为一行代码:var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath)); - Vargo

6

这对我来说作为一个通用解决方案可行。

public static Task<HttpResponseMessage> PostFormDataAsync<T>(this HttpClient httpClient, string url, string token, T data)
    {
        var content = new MultipartFormDataContent();

        foreach (var prop in data.GetType().GetProperties())
        {
            var value = prop.GetValue(data);
            if (value is FormFile)
            {
                var file = value as FormFile;
                content.Add(new StreamContent(file.OpenReadStream()), prop.Name, file.FileName);
                content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = prop.Name, FileName = file.FileName };
            }
            else
            {
                content.Add(new StringContent(JsonConvert.SerializeObject(value)), prop.Name);
            }
        }

        if (!string.IsNullOrWhiteSpace(token))
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return httpClient.PostAsync(url, content);
    }

你能写一个API控制器的例子吗?对于带有JSON数据的文件,需要任何自定义模型吗? - Ajt

4

通过使用以下代码解决:

        const string fileName = "csvFile.csv";
        var filePath = Path.Combine("IntegrationTests", fileName);
        var bytes = File.ReadAllBytes(filePath);
        var form = new MultipartFormDataContent();
        var content = new StreamContent(new MemoryStream(bytes));
        form.Add(content, "csvFile");
        content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
        {
            Name = "csvFile",
            FileName = fileName
        };
        content.Headers.Remove("Content-Type");
        content.Headers.Add("Content-Type", "application/octet-stream; boundary=----WebKitFormBoundaryMRxYYlVt8KWT8TU3");
        form.Add(content);

        //Act
        var postResponse = await _sellerClient.PostAsync("items/upload", form);

4
什么是 boundary=----WebKitFormBoundaryMRxYYlVt8KWT8TU3? - Enrico

3
请查看以下使用.NET 5.0环境的工作代码。
您将文件作为byte[]发送,并在API中将其作为IFormFile接收。
//api controller receiver

[HttpPost("SendBackupFiles")]
public IActionResult SendBackupFiles(IFormFile file)
{
    var filePath = Path.GetTempFileName();

    using (var stream = System.IO.File.Create(filePath)) 
        file.CopyToAsync(stream);
}



//client code sender example, not optimized lol.

const string filePath = @"C:\temp\hallo.csv";

using (var httpClient = new HttpClient())
{
    var form = new MultipartFormDataContent();
               
    byte[] fileData = File.ReadAllBytes(filePath);

    ByteArrayContent byteContent = new ByteArrayContent(fileData);

    byteContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
    
    form.Add(byteContent, "file", Path.GetFileName(filePath));

    var result = httpClient.PostAsync("http://localhost:5070/..yourControllerName.../SendBackupFiles", form).ConfigureAwait(false).GetAwaiter().GetResult().Content.ReadAsStringAsync().Result;
} 

这对我很有帮助。你在这里所做的是将字节数组包装为IFormFile。这对应于所提出的问题(即如何使发送方适应接收方)。然而,我很好奇,如果由于某种原因我们不能、不想或根本不会使发送方适应,那该怎么办呢?仅仅将控制器中的类型从IFormFile更改为byte[]是远远不够的,对吗?在这种情况下,你会推荐什么? - Konrad Viltersten

2
将附件作为MultipartFormDataContent发布。
var type = typeof(Startup);
            var stream = type.Assembly.GetManifestResourceStream(type, "Resources.New.docx");
        var fileContent = new StreamContent(stream);
var data = new MultipartFormDataContent
            {
                { fileContent, "file", "New.docx" }
            };

        var response = await _client.PostAsync("upload", multipartContent);

来源: https://medium.com/@woeterman_94/c-webapi-upload-files-to-a-controller-e5ccf288b0ca

本文将介绍如何在C# WebAPI中上传文件到控制器。我们将使用HttpPostedFileBase类来处理文件上传,并在控制器中创建一个方法,以便我们可以轻松地访问上传的文件。要开始,请确保您已经安装了WebAPI和MVC程序包。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接