使用HttpClient将大文件批量上传到Controller,IFormFile始终为空 - c#

我正在尝试创建.Net标准“客户端”类,以将文件(有时非常大)上载到Controller。我想通过将文件分成多个块并一次上传一个文件来做到这一点。目的是让其他应用程序使用此方法,而不是直接与Web Api通信。

我已经有Controller工作了。我已验证它是否可以使用支持节省块的Kendo-ui控件工作。

我遇到的问题是,从客户端类发布时,控制器的IEnumerable<IFormFile> files参数始终为空

控制者

[Route("api/Upload")]
public ActionResult ChunkSave(IEnumerable<IFormFile> files, string metaData, Guid id)
{
    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
    var serializer = new DataContractJsonSerializer(typeof(ChunkMetaData));
    ChunkMetaData somemetaData = serializer.ReadObject(ms) as ChunkMetaData;

    // The Name of the Upload component is "files"
    if (files != null)
    {
        // If this is the first chunk, try to delete the file so that we don't accidently
        // and up appending new bytes to the old file.
        if (somemetaData.ChunkIndex == 0)
        {
            _io.DeleteFile(id, Path.GetFileName(somemetaData.FileName));
        }

        foreach (var file in files)
        {
            // Some browsers send file names with full path. This needs to be stripped.
             _io.AppendToFile(id, Path.GetFileName(somemetaData.FileName), file.OpenReadStream());
        }
    }

    FileResult fileBlob = new FileResult();
    fileBlob.uploaded = somemetaData.TotalChunks - 1 <= somemetaData.ChunkIndex;
    fileBlob.fileUid = somemetaData.UploadUid;
    return new JsonResult(fileBlob);
}

客户:

public class FileTransferClient
{
    HttpClient Client { get; set; } 

    public FileTransferClient(Uri apiUrl)
    {
        this.Client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true })
        {
            BaseAddress = apiUrl
        };
        this.Client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task<bool> UploadFile(Guid id, Stream file, string name, string contentType)
    {
        bool ret = true;
        int chunckSize = 2097152; //2MB
        int totalChunks = (int)(file.Length / chunckSize);
        if (file.Length % chunckSize != 0)
        {
            totalChunks++;
        }

        for (int i = 0; i < totalChunks; i++)
        {
            long position = (i * (long)chunckSize);
            int toRead = (int)Math.Min(file.Length - position + 1, chunckSize);
            byte[] buffer = new byte[toRead];
            await file.ReadAsync(buffer, 0, toRead);

            MultipartFormDataContent content = new MultipartFormDataContent();
            content.Add(new StringContent(id.ToString()), "id");
            var meta = JsonConvert.SerializeObject(new ChunkMetaData
            {
                UploadUid = id.ToString(),
                FileName = name,
                ChunkIndex = i,
                TotalChunks = totalChunks,
                TotalFileSize = file.Length,
                ContentType = contentType
            });
            content.Add(new StringContent(meta), "metaData");
            using (var ms = new MemoryStream(buffer))
            {
                content.Add(new StreamContent(ms),"files");
                var response = await Client.PostAsync("/api/Upload", content).ConfigureAwait(false);
                if (!response.IsSuccessStatusCode)
                {
                    ret = false;
                    break;
                }
            }
        }
        return ret;
    }
}

参考方案

您的参数为空,因为您不是发送文件数组,而是发送一个文件。因此,绑定失败,并且您将获得null。分块的行为(实际上甚至没有做)并不等同于IEnumerable<IFormFile>;它仍然只是一个IFormFile

虽然由于要同时发送文件上载和其他一些帖子数据而需要以multipart/form-data的形式发送,但我认为您误会了它的实际作用。它只是意味着请求主体包含多种不同的mime类型,并不意味着它正在将文件上传为多个部分,这似乎就是您所想的。

流传输上载的实际行为发生在服务器端。它与服务器选择如何处理要上传的文件有关,而与用户如何上传无关。更具体地说,任何类型的模型绑定,尤其是IFormFile的绑定,都会导致文件先被后台处理到磁盘,然后再传递给您的操作。换句话说,如果您接受IFormFile,则说明您已经输掉了这场战斗。它已经从客户端完全转移到您的服务器。

ASP.NET Core docs向您展示了如何实际流式传输上传内容,并且毫不奇怪,其中包含了相当多的代码,您目前还没有。基本上,您必须完全在操作上关闭模型绑定,然后自己手动解析请求主体,请小心地对来自流的读取进行实际分块,而不要执行将全部操作立即强制进入内存的操作。

File_exists但不包含 - php

我正在尝试包含一个文件,但它似乎无法正常工作-这是整个代码:if (file_exists('config/categories.php')) { include ('config/categories.php'); } foreach ($categories as $cat_sef => $cat_name)…

获取PHP中函数调用者的__FILE__常量 - php

我知道PHP中的__FILE__魔术常数将变成当前执行文件的完整路径和文件名。但是,有什么方法可以使函数的调用文件获得相同的信息吗?例如://foo.php: include "bar.php"; call_it(); //bar.php function call_it() { echo "Calling file: …

File.Exists是否不能在UWP项目中使用? - c#

File.Exists(filePath);在控制台应用程序中可以完美地工作,但是当我在uwp中执行相同的操作时,它不会检测到文件。我试图在各种方法上设置断点,并尝试任何可以为我提供有关此问题的信息的方法,但是无论我尝试什么,我都一无所获。来自UWP应用的代码: string path = @"C:\Users\Name\Desktop\image…

我只想使用php和jquery而不是ajax与其他表单元素提交image(file) - php

我的HTML在这里<body> <form id="myform" method="POST" action="formprocessing.php" enctype="multipart/form-data"> <input type="…

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…