using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Apewer.Web { /// <summary>表示 API 行为结果,主体为流。</summary> public sealed class StreamResult : HeadResult, IDisposable { #region content /// <summary>主体。</summary> public Stream Stream { get; set; } /// <summary>Content-Length 的值,用于限制输出的最大长度。指定为 -1 时不限长度,输出到流的末尾。</summary> /// <value>Default = -1</value> public long Length { get; set; } /// <summary>输出后自动释放流。</summary> public bool AutoDispose { get; set; } /// <summary>创建结果实例。</summary> /// <param name="stream">要输出的流。</param> /// <param name="contentType">内容类型。</param> /// <param name="autoDispose">输出后自动释放流。</param> public StreamResult(Stream stream, string contentType = "application/octet-stream", bool autoDispose = true) : this(200, stream, contentType, -1, autoDispose) { } /// <summary>创建结果实例。</summary> /// <param name="status">HTTP 状态码。</param> /// <param name="stream">要输出的流。</param> /// <param name="contentType">内容类型。</param> /// <param name="length">Content-Length 的值。</param> /// <param name="autoDispose">输出后自动释放流。</param> public StreamResult(int status, Stream stream, string contentType = "application/octet-stream", long length = -1, bool autoDispose = true) : base(status) { Headers.Add("Content-Type", contentType); Stream = stream; Length = length; AutoDispose = autoDispose; } #endregion #region execute /// <summary>释放系统资源。</summary> public override void Dispose() { if (Stream != null) { RuntimeUtility.Dispose(Stream); Stream = null; } } /// <summary>写入 HTTP 头和主体。</summary> public override void ExecuteResult(ApiContext context) { try { if (Stream == null || Length == 0L) { WriteHead(context, 0); } else { WriteHead(context, Length); var writed = 0L; var capacity = 4096; var buffer = new byte[capacity]; var body = context.Provider.ResponseBody(); // 限制长度。 if (Length > 0L) { var remains = Length; while (true) { var limit = Math.Min((int)remains, capacity); var read = Stream.Read(buffer, 0, limit); if (read < 1) break; body.Write(buffer, 0, read); writed += read; remains -= read; if (remains < 1L) break; } } // 不限制长度,输出到流的末尾。 else { while (true) { var read = Stream.Read(buffer, 0, capacity); if (read < 1) break; body.Write(buffer, 0, read); writed += read; } } context.Provider.End(); } } finally { if (AutoDispose) Dispose(); } } #endregion } }