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.

207 lines
7.1 KiB

4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 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. if (ex.InnerException != null) ex = ex.InnerException;
  99. Logger.Write("Route Error", ex.GetType().FullName, ex.Message);
  100. var action = OnException;
  101. if (action != null) action.Invoke(Request, Response, route.Method, ex);
  102. else Response.Model = new ApiStatusModel(500);
  103. }
  104. return false;
  105. }
  106. void Default() { }
  107. void Execute(RouteItem route)
  108. {
  109. if (route == null)
  110. {
  111. Response.Model = new ApiStatusModel(404);
  112. return;
  113. }
  114. // 检查 HTTP 方法
  115. switch (Request.Method)
  116. {
  117. case Network.HttpMethod.GET:
  118. if (!route.Get)
  119. {
  120. Response.Model = new ApiStatusModel(405);
  121. return;
  122. }
  123. break;
  124. case Network.HttpMethod.POST:
  125. if (!route.Post)
  126. {
  127. Response.Model = new ApiStatusModel(405);
  128. return;
  129. }
  130. break;
  131. default:
  132. Response.Model = new ApiStatusModel(405);
  133. return;
  134. }
  135. // 准备参数。
  136. var pis = CollectionUtility.Vacuum(route.Parameters.Map(x => ApiParameter.Parse(x)));
  137. var ps = ReadParameters(Request, route.Parameters);
  138. // 准备控制器。
  139. var c = Activator.CreateInstance(route.Controller) as ApiController;
  140. c.Request = Request;
  141. c.Response = Response;
  142. // 调用 API 方法。
  143. var r = route.Method.Invoke(c, ps);
  144. // 格式化、返回。
  145. if (route.Return == null || route.Return.Equals(typeof(void))) return;
  146. Response.Model = Format(r) ?? new ApiStatusModel(204);
  147. }
  148. static ApiModel Format(object value)
  149. {
  150. var isNull = value.IsNull();
  151. var all = FormatAll;
  152. var formatter = Formatter;
  153. var customized = formatter != null;
  154. // 使用自定义格式化程序处理所有响应。
  155. if (all && customized) return formatter.Invoke(value);
  156. // 使用默认格式化。
  157. if (value is ApiModel model) return model;
  158. if (value is string text) return new ApiTextModel(text);
  159. if (value is byte[] bytes) return new ApiBytesModel(bytes);
  160. if (value is Json json) return new ApiJsonModel(json);
  161. if (value is HttpActionResult har) return har.ToModel();
  162. if (value is HttpResponseMessage hrm) return hrm.ToModel();
  163. // 指定了自定义格式化程序。
  164. if (customized) return formatter.Invoke(value);
  165. // 默认。
  166. return isNull ? null : new ApiTextModel(value.ToString());
  167. }
  168. #endregion
  169. }
  170. }