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.Internals.ApiHelper;
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;
}
#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 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 (r == null) return;
// 识别返回类型。
Response.Model = Model(r);
}
static ApiModel Model(object value)
{
if (value == null) return null;
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 ToModel(har);
if (value is HttpResponseMessage hrm) return ToModel(hrm);
return new ApiTextModel(value.ToString());
}
static ApiModel ToModel(HttpActionResult har)
{
if (har == null) return new ApiStatusModel(204);
var model = new ApiBytesModel();
model.Status = har.Status;
model.Bytes = har.Bytes;
model.ContentType = har.ContentType;
model.Attachment = har.Attachment;
return model;
}
static ApiModel ToModel(HttpResponseMessage hrm)
{
if (hrm == null) return new ApiStatusModel(204);
if (hrm.Content == null || hrm.Content.Stream == null) return new ApiStatusModel(204);
var model = new ApiStreamModel(hrm.Content.Stream);
model.Status = (int)hrm.StatusCode;
if (hrm.Content.Headers != null)
{
model.Headers = new StringPairs();
if (hrm.Content.Headers.ContentType != null) model.ContentType = hrm.Content.Headers.ContentType.MediaType;
if (hrm.Content.Headers.ContentDisposition != null) model.Attachment = hrm.Content.Headers.ContentDisposition.FileName;
model.Headers.Add("Content-Length", hrm.Content.Headers.ContentLength.ToString());
}
model.Stream = hrm.Content.Stream;
return model;
}
#endregion
}
}