using Apewer.Web; using System; using System.Collections.Generic; using System.Reflection; using System.Security.Cryptography; using System.Text; using static Apewer.NumberUtility; using static Apewer.Web.ApiUtility; namespace Apewer.AspNetBridge { /// 桥接 ASP.NET 的控制器。 public class BridgeController : Web.ApiController { #region static routes static RouteItem[] _routes = null; /// 导出所有路由项。 public static Json ExportRoutes() { var array = Json.NewArray(); if (_routes != null) { foreach (var route in _routes) { var item = route.ToJson(); array.AddItem(item); } } return array; } /// 初始化路由。 /// 包含控制器的程序集。 /// 包含返回 System.Void 的方法。 public static void Initialize(IEnumerable assemblies, bool withVoid = false) => _routes = RouteItem.Parse(assemblies, withVoid); /// 初始化路由,不包含返回 System.Void 的方法。 /// 包含控制器的程序集。 public static void Initialize(params Assembly[] assemblies) => _routes = RouteItem.Parse(assemblies, false); #endregion #region events /// 发生异常时候的处理程序。 public static OnException OnException { get; set; } /// 输出异常。 /// public static void Output(ApiRequest request, ApiResponse response, MethodInfo method, Exception exception) { if (request == null) throw new ArgumentNullException(nameof(request)); if (response == null) throw new ArgumentNullException(nameof(response)); if (method == null) throw new ArgumentNullException(nameof(method)); if (exception == null) throw new ArgumentNullException(nameof(exception)); var sb = new StringBuilder(); if (request.IP.NotEmpty()) { sb.Append(request.IP); sb.Append(" "); } sb.Append(request.Method.ToString()); if (request.Url != null) { sb.Append(" "); sb.Append(request.Url.OriginalString); } if (method != null) { sb.Append("\r\n"); sb.Append(method.DeclaringType.FullName); sb.Append("."); sb.Append(method.Name); } sb.Append("\r\n\r\n"); sb.Append(new ApiExceptionModel(exception).ToString()); var model = new ApiTextModel(sb.ToString()); model.Status = 500; response.Model = model; } /// 使用格式化程序处理所有响应。 /// /// 默认值:False( Bridge ) /// True:所有响应均使用自定义格式化程序,忽略 Bridge 内置程序。 /// False:优先使用 Bridge 内置程序格式化,对不支持的类型使用自定义程序。 /// public static bool FormatAll { get; set; } /// 自定义格式化程序。 public static Func Formatter { get; set; } #endregion #region instance /// public BridgeController() : base((c) => ((BridgeController)c).Execute(), (c) => ((BridgeController)c).Default()) { } bool Execute() { if (_routes == null) Initialize(); var routes = _routes; var route = RouteItem.Match(routes, Request.Url.AbsolutePath, Request.Method); try { Execute(route); } catch (Exception ex) { Logger.Write("Route Error", ex.InnerException.GetType().FullName, ex.InnerException.Message); var action = OnException; if (action != null) action.Invoke(Request, Response, route.Method, ex.InnerException); else Response.Model = new ApiStatusModel(500); } return false; } void Default() { } void Execute(RouteItem route) { if (route == null) { Response.Model = new ApiStatusModel(404); return; } // 检查 HTTP 方法 switch (Request.Method) { case Network.HttpMethod.GET: if (!route.Get) { Response.Model = new ApiStatusModel(405); return; } break; case Network.HttpMethod.POST: if (!route.Post) { Response.Model = new ApiStatusModel(405); return; } break; default: Response.Model = new ApiStatusModel(405); return; } // 准备参数。 var pis = CollectionUtility.Vacuum(route.Parameters.Map(x => ApiParameter.Parse(x))); var ps = ReadParameters(Request, route.Parameters); // 准备控制器。 var c = Activator.CreateInstance(route.Controller) as ApiController; c.Request = Request; c.Response = Response; // 调用 API 方法。 var r = route.Method.Invoke(c, ps); // 格式化、返回。 if (route.Return == null || route.Return.Equals(typeof(void))) return; Response.Model = Format(r) ?? new ApiStatusModel(204); } static ApiModel Format(object value) { var isNull = value.IsNull(); var all = FormatAll; var formatter = Formatter; var customized = formatter != null; // 使用自定义格式化程序处理所有响应。 if (all && customized) return formatter.Invoke(value); // 使用默认格式化。 if (value is ApiModel model) return model; if (value is string text) return new ApiTextModel(text); if (value is byte[] bytes) return new ApiBytesModel(bytes); if (value is Json json) return new ApiJsonModel(json); if (value is HttpActionResult har) return har.ToModel(); if (value is HttpResponseMessage hrm) return hrm.ToModel(); // 指定了自定义格式化程序。 if (customized) return formatter.Invoke(value); // 默认。 return isNull ? null : new ApiTextModel(value.ToString()); } #endregion } }