【发布时间】:2020-07-09 13:45:53
【问题描述】:
假设我在具有 1GB 存储和 1GB RAM 的设备上运行 .NET Core API。我想将文件从我的网站直接上传到 FTP 服务器,而不会将文件缓存在内存或磁盘中。我有这个用于下载文件的工作,因为我基本上充当代理,通过在流中打开 FTP 文件,然后将其直接流式传输到 HttpContext.Request.Body。
为了上传,我想立即点击控制器。我现在可以看到它缓存到磁盘,这可能是因为我的EnableBuffering 属性。我有一个常规的<form method="post" enctype="multipart/form-data">,它会发布到我的 .NET Core 后端。控制器如下所示:
[EnableBuffering]
[RequestFormLimits(ValueLengthLimit = int.MaxValue, MultipartBodyLengthLimit = long.MaxValue)]
[HttpPost("[action]")]
public async Task<IActionResult> Upload(string path)
{
if (!IsMultipartContentType(HttpContext.Request.ContentType))
return BadRequest("Not multipart request");
await _fileProvider.Upload(path);
return Ok();
}
启用缓冲:
public class EnableBufferingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.HttpContext.Request.EnableBuffering();
}
public void OnResourceExecuted(ResourceExecutedContext context) {}
}
上传逻辑:
public async Task Upload(string path)
{
const int buffer = 8 * 1024;
var request = _httpContextAccessor.HttpContext.Request;
var boundary = request.GetMultipartBoundary();
var reader = new MultipartReader(boundary, request.Body, buffer);
var section = await reader.ReadNextSectionAsync();
using (var client = await _ftpHelper.GetFtpClient())
{
while (section != null)
{
var fileSection = section.AsFileSection();
if (fileSection != null)
{
var fileName = fileSection.FileName;
var uploadPath = Path.Combine(path, fileName);
var stream = await client.OpenWriteAsync(uploadPath);
await section.Body.CopyToAsync(stream, buffer);
}
section = await reader.ReadNextSectionAsync();
}
}
}
如果我不启用缓冲,我会得到:
System.IO.IOException: Stream 意外结束,内容可能已被另一个组件读取。
但是,通过启用缓冲,我可以看到它说:
确保 requestBody 可以被多次读取。通常在内存中缓冲请求体; 将大于 30K 字节的请求写入磁盘。
所以这部分是有道理的。但是,我该如何解决这个问题?如果我在Upload() 方法的第一行设置断点,然后开始上传,它首先上传文件然后 命中断点。
我能否解决这个问题,让它立即访问我的控制器并开始上传到 FTP 服务器,而不先保存到磁盘?
【问题讨论】:
-
尝试使用日志输出而不是设置断点,因为它可能会干扰上传工作流
-
@HirasawaYui 我可以保证在上传完成之前它不会撞到控制器。通过构建和部署到生产环境进行测试。
-
您将需要缓冲,但只需使用一个小缓冲区。 CopyTo 中使用的默认缓冲区大小为 82kb,这意味着您可以传输大文件,而每次传输仅使用 82kb 内存
-
@MalteR 是的,没错,但是,这并不能解决我在磁盘上缓存文件的问题。即使我删除了 EnableBuffering 属性,它仍然会先上传文件,同时暂时保存到磁盘,然后再访问我的控制器。
标签: c# asp.net-core .net-core fluentftp