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.

206 lines
7.1 KiB

4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
11 months ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
  1. using Apewer.Web;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using static Apewer.NumberUtility;
  8. using static Apewer.Web.ApiUtility;
  9. namespace Apewer.AspNetBridge
  10. {
  11. /// <summary>桥接 ASP.NET 的控制器。</summary>
  12. public class BridgeController : Web.ApiController
  13. {
  14. #region static routes
  15. static RouteItem[] _routes = null;
  16. /// <summary>导出所有路由项。</summary>
  17. public static Json ExportRoutes()
  18. {
  19. var array = Json.NewArray();
  20. if (_routes != null)
  21. {
  22. foreach (var route in _routes)
  23. {
  24. var item = route.ToJson();
  25. array.AddItem(item);
  26. }
  27. }
  28. return array;
  29. }
  30. /// <summary>初始化路由。</summary>
  31. /// <param name="assemblies">包含控制器的程序集。</param>
  32. /// <param name="withVoid">包含返回 System.Void 的方法。</param>
  33. public static void Initialize(IEnumerable<Assembly> assemblies, bool withVoid = false) => _routes = RouteItem.Parse(assemblies, withVoid);
  34. /// <summary>初始化路由,不包含返回 System.Void 的方法。</summary>
  35. /// <param name="assemblies">包含控制器的程序集。</param>
  36. public static void Initialize(params Assembly[] assemblies) => _routes = RouteItem.Parse(assemblies, false);
  37. #endregion
  38. #region events
  39. /// <summary>发生异常时候的处理程序。</summary>
  40. public static OnException OnException { get; set; }
  41. /// <summary>输出异常。</summary>
  42. /// <exception cref="ArgumentNullException"></exception>
  43. public static void Output(ApiRequest request, ApiResponse response, MethodInfo method, Exception exception)
  44. {
  45. if (request == null) throw new ArgumentNullException(nameof(request));
  46. if (response == null) throw new ArgumentNullException(nameof(response));
  47. if (method == null) throw new ArgumentNullException(nameof(method));
  48. if (exception == null) throw new ArgumentNullException(nameof(exception));
  49. var sb = new StringBuilder();
  50. if (request.IP.NotEmpty())
  51. {
  52. sb.Append(request.IP);
  53. sb.Append(" ");
  54. }
  55. sb.Append(request.Method.ToString());
  56. if (request.Url != null)
  57. {
  58. sb.Append(" ");
  59. sb.Append(request.Url.OriginalString);
  60. }
  61. if (method != null)
  62. {
  63. sb.Append("\r\n");
  64. sb.Append(method.DeclaringType.FullName);
  65. sb.Append(".");
  66. sb.Append(method.Name);
  67. }
  68. sb.Append("\r\n\r\n");
  69. sb.Append(new ApiExceptionModel(exception).ToString());
  70. var model = new ApiTextModel(sb.ToString());
  71. model.Status = 500;
  72. response.Model = model;
  73. }
  74. /// <summary>使用格式化程序处理所有响应。</summary>
  75. /// <remarks>
  76. /// <para>默认值:False( Bridge )</para>
  77. /// <para>True:所有响应均使用自定义格式化程序,忽略 Bridge 内置程序。</para>
  78. /// <para>False:优先使用 Bridge 内置程序格式化,对不支持的类型使用自定义程序。</para>
  79. /// </remarks>
  80. public static bool FormatAll { get; set; }
  81. /// <summary>自定义格式化程序。</summary>
  82. public static Func<object, ApiModel> Formatter { get; set; }
  83. #endregion
  84. #region instance
  85. /// <summary></summary>
  86. public BridgeController() : base((c) => ((BridgeController)c).Execute(), (c) => ((BridgeController)c).Default()) { }
  87. bool Execute()
  88. {
  89. if (_routes == null) Initialize();
  90. var routes = _routes;
  91. var route = RouteItem.Match(routes, Request.Url.AbsolutePath, Request.Method);
  92. try
  93. {
  94. Execute(route);
  95. }
  96. catch (Exception ex)
  97. {
  98. Logger.Write("Route Error", ex.InnerException.GetType().FullName, ex.InnerException.Message);
  99. var action = OnException;
  100. if (action != null) action.Invoke(Request, Response, route.Method, ex.InnerException);
  101. else Response.Model = new ApiStatusModel(500);
  102. }
  103. return false;
  104. }
  105. void Default() { }
  106. void Execute(RouteItem route)
  107. {
  108. if (route == null)
  109. {
  110. Response.Model = new ApiStatusModel(404);
  111. return;
  112. }
  113. // 检查 HTTP 方法
  114. switch (Request.Method)
  115. {
  116. case Network.HttpMethod.GET:
  117. if (!route.Get)
  118. {
  119. Response.Model = new ApiStatusModel(405);
  120. return;
  121. }
  122. break;
  123. case Network.HttpMethod.POST:
  124. if (!route.Post)
  125. {
  126. Response.Model = new ApiStatusModel(405);
  127. return;
  128. }
  129. break;
  130. default:
  131. Response.Model = new ApiStatusModel(405);
  132. return;
  133. }
  134. // 准备参数。
  135. var pis = CollectionUtility.Vacuum(route.Parameters.Map(x => ApiParameter.Parse(x)));
  136. var ps = ReadParameters(Request, route.Parameters);
  137. // 准备控制器。
  138. var c = Activator.CreateInstance(route.Controller) as ApiController;
  139. c.Request = Request;
  140. c.Response = Response;
  141. // 调用 API 方法。
  142. var r = route.Method.Invoke(c, ps);
  143. // 格式化、返回。
  144. if (route.Return == null || route.Return.Equals(typeof(void))) return;
  145. Response.Model = Format(r) ?? new ApiStatusModel(204);
  146. }
  147. static ApiModel Format(object value)
  148. {
  149. var isNull = value.IsNull();
  150. var all = FormatAll;
  151. var formatter = Formatter;
  152. var customized = formatter != null;
  153. // 使用自定义格式化程序处理所有响应。
  154. if (all && customized) return formatter.Invoke(value);
  155. // 使用默认格式化。
  156. if (value is ApiModel model) return model;
  157. if (value is string text) return new ApiTextModel(text);
  158. if (value is byte[] bytes) return new ApiBytesModel(bytes);
  159. if (value is Json json) return new ApiJsonModel(json);
  160. if (value is HttpActionResult har) return har.ToModel();
  161. if (value is HttpResponseMessage hrm) return hrm.ToModel();
  162. // 指定了自定义格式化程序。
  163. if (customized) return formatter.Invoke(value);
  164. // 默认。
  165. return isNull ? null : new ApiTextModel(value.ToString());
  166. }
  167. #endregion
  168. }
  169. }