在 C# .Net 5 中分块文件

Chunking Files in C# .Net 5

我有很大的视频文件,我试图分解成块并在服务器端重新组合。我大部分时间都在遵循 this article 中的建议,但我遇到了一些问题。

在捆绑数据块并通过网络发送它们的代码中,我有以下代码:

     using (var client = new HttpClient(clientHandler))
        {
            var requestUri = ApiHelper.GetUrl("api/uploadFile");
            client.BaseAddress = new Uri(requestUri);
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add(Constants.ApiKeyHeaderName, Constants.RoadLivesApiAppKey);

            using (var content = new MultipartFormDataContent())
            {
                var fileBytes = System.IO.File.ReadAllBytes(fileName);
                var fileContent = new ByteArrayContent(fileBytes);
                fileContent.Headers.ContentDisposition = new
                    ContentDispositionHeaderValue("attachment")
                {
                    FileName = Path.GetFileName(fileName)
                };
                content.Add(fileContent);

                try
                {
                    var result = client.PostAsync(requestUri, content).Result;
                    rslt = true;
                }
                catch (Exception ex)
                {
                    rslt = false;
                }
            }
        }

在服务器端,我正在尝试将该内容作为字节数组取回,以便在上传所有内容后重新组合文件。链接的文章建议使用 Request.Files,它在 .NET 5 中不存在。我尝试使用 Request.Form.Files,但整个 Request.Form 显示为空。

对于如何从 Request 对象获取 ByteArrayContent 有什么建议吗? Request.ContentLength 符合我的预期,但我不确定从哪里可以获取该数据。

我已尝试根据以下选项从 Request.Body 中获取 ByteArrayContent,但它没有按预期工作。

        byte[] bodByteArray;
        MemoryStream ms = new MemoryStream();
        Request.BodyReader.CopyToAsync(ms);
        //Request.Body.CopyToAsync(ms);
        bodByteArray = ms.ToArray();

一切都简单多了。这是一个例子:
服务器:

using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Example.Controllers
{
    [ApiController]
    [Route("api/v1/[controller]")]
    public class UploadController : ControllerBase
    {
        [HttpPost]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public async Task PostAsync(
            CancellationToken cancellationToken = default)
        {
            byte[] bytes;

            // To get bytes, use this code (await is required, you missed it)
            // But I recommend working with Stream in order not to load the server's RAM.
            using (var memoryStream = new MemoryStream())
            {
                await Request.BodyReader.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
                bytes = memoryStream.ToArray();
            }

            // use bytes here
        }
    }
}

客户:

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

namespace Example.Apis
{
    public partial class ExampleApi
    {
        public async Task UploadAsync(
            string path,
            CancellationToken cancellationToken = default)
        {
            using var client = new HttpClient();

            using var request = new HttpRequestMessage(
                HttpMethod.Post,
                new Uri("https://localhost:5001/api/v1/upload"))
            {
                Content = new StreamContent(File.OpenRead(path)),
            };
            
            using var response = await client.SendAsync(
                request, cancellationToken).ConfigureAwait(false);

            response.EnsureSuccessStatusCode();
        }
    }
}

P.S。除了示例,我建议您了解 Streams,这是处理大文件的正确方法。