C# ASP.NET Web API如何从服务器端监控流传输进度?
监控ASP.NET Web API流传输进度的简便方案
方案1:装饰器模式包装流(推荐)
不用完全继承实现Stream的所有抽象方法,只需创建一个包装流,仅重写Read方法处理进度,其余方法直接委托给原始流即可,大幅减少代码量:
public class ProgressStream : Stream { private readonly Stream _baseStream; private readonly Action<long> _progressCallback; private long _bytesRead; public ProgressStream(Stream baseStream, Action<long> progressCallback) { _baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); _progressCallback = progressCallback ?? throw new ArgumentNullException(nameof(progressCallback)); } // 仅重写Read方法监控进度 public override int Read(byte[] buffer, int offset, int count) { int bytesRead = _baseStream.Read(buffer, offset, count); if (bytesRead > 0) { _bytesRead += bytesRead; _progressCallback(_bytesRead); } return bytesRead; } // 其余方法直接复用原始流逻辑,无需自行实现 public override bool CanRead => _baseStream.CanRead; public override bool CanSeek => _baseStream.CanSeek; public override bool CanWrite => _baseStream.CanWrite; public override long Length => _baseStream.Length; public override long Position { get => _baseStream.Position; set => _baseStream.Position = value; } public override void Flush() => _baseStream.Flush(); public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin); public override void SetLength(long value) => _baseStream.SetLength(value); public override void Write(byte[] buffer, int offset, int count) => _baseStream.Write(buffer, offset, count); protected override void Dispose(bool disposing) { if (disposing) { _baseStream.Dispose(); } base.Dispose(disposing); } }
使用示例
结合你现有代码,只需将原始FileStream包装为ProgressStream,传入进度处理逻辑:
var filePath = @"c:\largefile.tmp"; using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); // 包装流并传入进度回调(比如记录日志、统计传输量) using var progressStream = new ProgressStream(fs, bytesRead => { var totalBytes = fs.Length; var progressPercent = (double)bytesRead / totalBytes * 100; Console.WriteLine($"已传输 {bytesRead}/{totalBytes} 字节,进度:{progressPercent:F2}%"); }); var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(progressStream, 8192) };
方案2:自定义HttpContent
若不想包装流,也可直接扩展HttpContent,重写SerializeToStreamAsync方法监控传输进度:
public class ProgressStreamContent : StreamContent { private readonly long _totalBytes; private readonly Action<long> _progressCallback; private long _bytesWritten; public ProgressStreamContent(Stream stream, int bufferSize, long totalBytes, Action<long> progressCallback) : base(stream, bufferSize) { _totalBytes = totalBytes; _progressCallback = progressCallback; } protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context) { var buffer = new byte[this.BufferSize]; int bytesRead; while ((bytesRead = await this.Content.ReadAsync(buffer, 0, buffer.Length)) > 0) { await stream.WriteAsync(buffer, 0, bytesRead); _bytesWritten += bytesRead; _progressCallback(_bytesWritten); } } }
使用示例
var filePath = @"c:\largefile.tmp"; using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); var totalBytes = fs.Length; var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ProgressStreamContent(fs, 8192, totalBytes, bytesWritten => { var progressPercent = (double)bytesWritten / totalBytes * 100; Console.WriteLine($"已传输 {bytesWritten}/{totalBytes} 字节,进度:{progressPercent:F2}%"); }) };
方案优势
- 装饰器流仅需实现核心的进度监控逻辑,其余方法复用原始流能力,避免了完全实现
Stream抽象类的冗余工作; - 自定义
HttpContent贴合Web API响应场景,无需额外流包装,逻辑更聚焦。
内容的提问来源于stack exchange,提问作者Edison C
相关产品推荐
相关产品推荐

