You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.9 KiB

11 months ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. namespace Apewer.Web
  6. {
  7. /// <summary>表示 API 行为结果,主体为流。</summary>
  8. public sealed class StreamResult : HeadResult, IDisposable
  9. {
  10. #region content
  11. /// <summary>主体。</summary>
  12. public Stream Stream { get; set; }
  13. /// <summary>Content-Length 的值,用于限制输出的最大长度。指定为 -1 时不限长度,输出到流的末尾。</summary>
  14. /// <value>Default = -1</value>
  15. public long Length { get; set; }
  16. /// <summary>输出后自动释放流。</summary>
  17. public bool AutoDispose { get; set; }
  18. /// <summary>创建结果实例。</summary>
  19. /// <param name="stream">要输出的流。</param>
  20. /// <param name="contentType">内容类型。</param>
  21. /// <param name="autoDispose">输出后自动释放流。</param>
  22. public StreamResult(Stream stream, string contentType = "application/octet-stream", bool autoDispose = true) : this(200, stream, contentType, -1, autoDispose) { }
  23. /// <summary>创建结果实例。</summary>
  24. /// <param name="status">HTTP 状态码。</param>
  25. /// <param name="stream">要输出的流。</param>
  26. /// <param name="contentType">内容类型。</param>
  27. /// <param name="length">Content-Length 的值。</param>
  28. /// <param name="autoDispose">输出后自动释放流。</param>
  29. public StreamResult(int status, Stream stream, string contentType = "application/octet-stream", long length = -1, bool autoDispose = true) : base(status)
  30. {
  31. Headers.Add("Content-Type", contentType);
  32. Stream = stream;
  33. Length = length;
  34. AutoDispose = autoDispose;
  35. }
  36. #endregion
  37. #region execute
  38. /// <summary>释放系统资源。</summary>
  39. public override void Dispose()
  40. {
  41. if (Stream != null)
  42. {
  43. RuntimeUtility.Dispose(Stream);
  44. Stream = null;
  45. }
  46. }
  47. /// <summary>写入 HTTP 头和主体。</summary>
  48. public override void ExecuteResult(ApiContext context)
  49. {
  50. try
  51. {
  52. if (Stream == null || Length == 0L)
  53. {
  54. WriteHead(context, 0);
  55. }
  56. else
  57. {
  58. WriteHead(context, Length);
  59. var writed = 0L;
  60. var capacity = 4096;
  61. var buffer = new byte[capacity];
  62. var body = context.Provider.ResponseBody();
  63. // 限制长度。
  64. if (Length > 0L)
  65. {
  66. var remains = Length;
  67. while (true)
  68. {
  69. var limit = Math.Min((int)remains, capacity);
  70. var read = Stream.Read(buffer, 0, limit);
  71. if (read < 1) break;
  72. body.Write(buffer, 0, read);
  73. writed += read;
  74. remains -= read;
  75. if (remains < 1L) break;
  76. }
  77. }
  78. // 不限制长度,输出到流的末尾。
  79. else
  80. {
  81. while (true)
  82. {
  83. var read = Stream.Read(buffer, 0, capacity);
  84. if (read < 1) break;
  85. body.Write(buffer, 0, read);
  86. writed += read;
  87. }
  88. }
  89. context.Provider.End();
  90. }
  91. }
  92. finally
  93. {
  94. if (AutoDispose) Dispose();
  95. }
  96. }
  97. #endregion
  98. }
  99. }