假设我在具有 1GB 存储和 1GB RAM 的设备上运行 .NET Core API。我想将文件从我的网站直接上传到 FTP 服务器,而不会将文件缓存在内存或磁盘中。我有这个用于下载文件的工作,因为我基本上充当代理,通过在流中打开 FTP 文件,然后将其直接流式传输到HttpContext.Request.Body
.
对于上传,我想立即点击控制器。我现在可以看到它缓存到磁盘,这可能是因为我的EnableBuffering
属性。我有一个<form method="post" enctype="multipart/form-data">
POST 到我的 .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 服务器,而不先保存到磁盘吗?