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.

239 lines
8.0 KiB

4 years ago
  1. #if NETCORE
  2. using Microsoft.AspNetCore.Http;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Text;
  7. namespace Apewer.Web
  8. {
  9. /// <summary>用于网站的服务程序。</summary>
  10. public class AspNetCoreProvider : ApiProvider
  11. {
  12. private HttpContext context;
  13. private HttpRequest request;
  14. private HttpResponse response;
  15. /// <summary>创建服务程序实例。</summary>
  16. /// <exception cref="ArgumentNullException"></exception>
  17. public AspNetCoreProvider(HttpContext context)
  18. {
  19. if (context == null) throw new ArgumentNullException(nameof(context));
  20. this.context = context;
  21. request = context.Request;
  22. response = context.Response;
  23. }
  24. #region Implement
  25. /// <summary>调用前的检查,返回错误信息。</summary>
  26. public override string PreInvoke() { return null; }
  27. /// <summary>读取请求前的检查,返回错误信息。</summary>
  28. public override string PreRead() { return null; }
  29. /// <summary>写入响应前的检查,返回错误信息。</summary>
  30. public override string PreWrite() { return null; }
  31. /// <summary>结束本次请求和响应。</summary>
  32. public override void End() { }
  33. /// <summary>释放非托管资源。</summary>
  34. public override void Dispose() { }
  35. #endregion
  36. #region Request
  37. /// <summary>获取 HTTP 方法。</summary>
  38. public override Network.HttpMethod GetMethod() => ApiUtility.Method(request.Method);
  39. /// <summary>获取客户端的 IP 地址。</summary>
  40. public override string GetClientIP() => request.HttpContext.Connection.RemoteIpAddress.ToString();
  41. /// <summary>获取请求的 URL。</summary>
  42. public override Uri GetUrl()
  43. {
  44. var https = request.IsHttps;
  45. var port = context.Connection.LocalPort;
  46. var query = request.QueryString == null ? null : request.QueryString.Value;
  47. var sb = new StringBuilder();
  48. sb.Append(https ? "https://" : "http://");
  49. sb.Append(request.Host.Host ?? "");
  50. if ((https && port != 443) || (!https && port != 80))
  51. {
  52. sb.Append(":");
  53. sb.Append(port);
  54. }
  55. sb.Append(request.Path);
  56. if (!string.IsNullOrEmpty(query))
  57. {
  58. if (!query.StartsWith("?")) sb.Append("?");
  59. sb.Append(query);
  60. }
  61. var url = sb.ToString();
  62. var uri = new Uri(url);
  63. return uri;
  64. }
  65. /// <summary>获取请求的 Referrer。</summary>
  66. public override string GetReferrer() => null;
  67. /// <summary>获取请求的头。</summary>
  68. public override StringPairs GetHeaders()
  69. {
  70. var headers = request.Headers;
  71. var sp = new StringPairs();
  72. if (headers == null) return sp;
  73. foreach (var key in headers.Keys)
  74. {
  75. if (string.IsNullOrEmpty(key)) continue;
  76. try
  77. {
  78. var value = headers[key];
  79. if (string.IsNullOrEmpty(value)) continue;
  80. sp.Add(key, value);
  81. }
  82. catch { }
  83. }
  84. return sp;
  85. }
  86. /// <summary>获取请求的内容类型。</summary>
  87. public override string GetContentType() => request.ContentType;
  88. /// <summary>获取请求的内容长度。</summary>
  89. public override long GetContentLength() => request.ContentLength ?? -1L;
  90. /// <summary>获取请求的内容。</summary>
  91. public override Stream RequestBody() => request.Body;
  92. #endregion
  93. #region Response
  94. /// <summary>设置 HTTP 状态。</summary>
  95. public override void SetStatus(string status) => response.StatusCode = Convert.ToInt32(status);
  96. /// <summary>设置响应的头。</summary>
  97. public override string SetHeader(string name, string value)
  98. {
  99. try { response.Headers.Add(name, value); }
  100. catch (Exception ex) { return ex.Message; }
  101. return null;
  102. }
  103. /// <summary>设置响应的缓存秒数,设置为 0 即不允许缓存。</summary>
  104. public override void SetCache(int seconds)
  105. {
  106. if (seconds > 0)
  107. {
  108. SetHeader("Cache-Control", $"public, max-age={seconds}, s-maxage={seconds}");
  109. }
  110. else
  111. {
  112. SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  113. SetHeader("Pragma", "no-cache");
  114. }
  115. }
  116. /// <summary>设置响应的缓存秒数。</summary>
  117. public override void SetContentType(string value) => response.ContentType = value;
  118. /// <summary>设置响应的内容长度。</summary>
  119. public override void SetContentLength(long value) => response.ContentLength = value;
  120. /// <summary>设置响应重定向。</summary>
  121. public override void SetRedirect(string location) => SetRedirect(location, false);
  122. /// <summary>获取 Response 流。</summary>
  123. public override Stream ResponseBody() => response.Body;
  124. #endregion
  125. #region This
  126. /// <summary>将客户端重新定向到新 URL。</summary>
  127. /// <remarks>默认响应 302 状态。可指定 permanent = true 以响应 301 状态。</remarks>
  128. public void SetRedirect(string location, bool permanent = false)
  129. {
  130. try { response.Redirect(location, permanent); } catch { }
  131. }
  132. private static void Async(Stream source, Stream destination, Func<long, bool> progress = null, int buffer = 4096, Action after = null)
  133. {
  134. if (source == null || !source.CanRead || destination == null || !destination.CanWrite)
  135. {
  136. after?.Invoke();
  137. return;
  138. }
  139. Async(source, destination, progress, buffer, after, 0L);
  140. }
  141. private static void Async(Stream source, Stream destination, Func<long, bool> progress, int buffer, Action after, long total)
  142. {
  143. // 缓冲区。
  144. var limit = buffer < 1 ? 1 : buffer;
  145. var temp = new byte[limit];
  146. // 读取一次。
  147. try
  148. {
  149. source.BeginRead(temp, 0, limit, (ar1) =>
  150. {
  151. var count = source.EndRead(ar1);
  152. if (count > 0)
  153. {
  154. destination.BeginWrite(temp, 0, count, (ar2) =>
  155. {
  156. destination.EndWrite(ar2);
  157. total += count;
  158. if (progress != null)
  159. {
  160. var @continue = progress.Invoke(total);
  161. if (!@continue)
  162. {
  163. after?.Invoke();
  164. return;
  165. }
  166. }
  167. Async(source, destination, progress, buffer, after, total);
  168. }, null);
  169. }
  170. else after?.Invoke();
  171. }, null);
  172. }
  173. catch { }
  174. }
  175. /// <summary>解析 URL 的查询字符串,获取所有已解码的参数。</summary>
  176. public static StringPairs ParseQuery(HttpRequest request)
  177. {
  178. if (request == null) return new StringPairs();
  179. var sp = new StringPairs();
  180. if (request.Query == null) return sp;
  181. var keys = request.Query.Keys;
  182. sp.Capacity = keys.Count;
  183. foreach (var key in keys)
  184. {
  185. sp.Add(key, request.Query[key]);
  186. }
  187. sp.Capacity = sp.Count;
  188. return sp;
  189. }
  190. #endregion
  191. }
  192. }
  193. #endif