如何解决ASP.NET Core 3.1 在HttpPut 请求中读取流文件上传问题
问题陈述:
我正在尝试使用 Request.Body 流在 HttpPut 请求中迭代流式文件上传,但我真的很困难,我的 google-fu 几乎没有出现。情况是我希望这样的事情可以工作,但它没有:
[HttpPut("{accountName}/{subAccount}/{revisionId}/{randomNumber}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> Puttest()
{
var memStream = new MemoryStream();
var b = new Memory<byte>();
int totalBytes = 0;
int bytesRead = 0;
byte[] buffer = new byte[1024];
do
{
bytesRead = await Request.Body.ReadAsync(new Memory<byte>(buffer),CancellationToken.None);
totalBytes += bytesRead;
await memStream.WriteAsync(buffer,bytesRead);
} while (bytesRead > 0);
return Ok(memStream);
}
在调试器中,我可以检查 Request.Body 并查看它的内部 _buffer
。它包含所需的数据。当上面的代码运行时,MemoryStream
全是零。在“读取”期间,缓冲区也充满零。 Request.Body 的长度也为 0。
目标:
使用 HttpPut 请求通过流式传输上传文件,以块的形式对其进行迭代,进行一些处理,然后使用 gRPC 将这些块流式传输到另一个端点。我想避免将整个文件读入内存。
我尝试过的:
这有效:
using (var sr = new StreamReader(Request.Body))
{
var body = await sr.ReadToEndAsync();
return Ok(body);
}
该代码会将所有 Stream 作为字符串读取到内存中,这是非常不受欢迎的,但它向我证明了 Request.Body 数据可以在我正在使用的方法中以某种方式读取。
在 Startup.cs 类的配置方法中,我包含了以下内容以确保启用缓冲:
app.Use(async (context,next) => {
context.Request.EnableBuffering();
await next();
});
我尝试将 Request.Body 封装在另一个流中,例如 BufferedStream
和 filebufferingReadStream
,但这些都没有区别。
我试过了:
var reader = new BinaryReader(Request.Body,Encoding.Default);
do
{
bytesRead = reader.Read(buffer,buffer.Length);
await memStream.WriteAsync(buffer);
} while (bytesRead > 0);
这也会产生一个全为零的 MemoryStream
。
解决方法
我在当前项目中经常使用这种请求正文流。
这对我来说非常好:
[HttpPut("{accountName}/{subAccount}/{revisionId}/{randomNumber}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> PutTest(CancellationToken cancel) {
using (var to = new MemoryStream()) {
var from = HttpContext.Request.Body;
var buffer = new byte[8 * 1024];
long totalBytes = 0;
int bytesRead;
while ((bytesRead = await from.ReadAsync(buffer,buffer.Length,cancel)) > 0) {
await to.WriteAsync(buffer,bytesRead,cancel);
totalBytes += bytesRead;
}
return Ok(to);
}
}
我所做的唯一不同的是:
- 我正在范围上下文中创建
MemoryStream
(使用)。 - 我使用了一个稍大的缓冲区(一些试验和错误使我达到了这个特定的大小)
- 我使用了不同的
Stream.ReadAsync
重载,我在其中传递bytes[]
缓冲区、读取长度和读取开始位置为 0。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。