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.
|
|
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 {
/// <summary>桥接 ASP.NET 的控制器。</summary>
public class BridgeController : Web.ApiController {
#region static routes
static RouteItem[] _routes = null;
/// <summary>导出所有路由项。</summary>
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; }
/// <summary>初始化路由。</summary>
/// <param name="assemblies">包含控制器的程序集。</param>
/// <param name="withVoid">包含返回 System.Void 的方法。</param>
public static void Initialize(IEnumerable<Assembly> assemblies, bool withVoid = false) => _routes = RouteItem.Parse(assemblies, withVoid);
/// <summary>初始化路由,不包含返回 System.Void 的方法。</summary>
/// <param name="assemblies">包含控制器的程序集。</param>
public static void Initialize(params Assembly[] assemblies) => _routes = RouteItem.Parse(assemblies, false);
#endregion
#region events
/// <summary>发生异常时候的处理程序。</summary>
public static OnException OnException { get; set; }
/// <summary>输出异常。</summary>
/// <exception cref="ArgumentNullException"></exception>
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; }
/// <summary>使用格式化程序处理所有响应。</summary>
/// <remarks>
/// <para>默认值:False( Bridge )</para>
/// <para>True:所有响应均使用自定义格式化程序,忽略 Bridge 内置程序。</para>
/// <para>False:优先使用 Bridge 内置程序格式化,对不支持的类型使用自定义程序。</para>
/// </remarks>
public static bool FormatAll { get; set; }
/// <summary>自定义格式化程序。</summary>
public static Func<object, ApiModel> Formatter { get; set; }
#endregion
#region instance
/// <summary></summary>
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
}
}
|