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.

199 lines
7.5 KiB

using Apewer.Network;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Apewer.AspNetBridge
{
[Serializable]
internal class RouteItem : IToJson
{
public string Path;
public string Lower;
public Type Controller;
public MethodInfo Method;
public string MethodName;
public bool Connect;
public bool Delete;
public bool Get;
public bool Head;
public bool Options;
public bool Patch;
public bool Post;
public bool Put;
public bool Trace;
public ParameterInfo[] Parameters;
public Type Return;
public Json ToJson()
{
var ps = Json.NewObject();
foreach (var parameter in Parameters) ps.SetProperty(parameter.Name, parameter.ParameterType.FullName);
var methods = Json.NewArray();
if (Connect) methods.AddItem("connect");
if (Delete) methods.AddItem("delete");
if (Get) methods.AddItem("get");
if (Head) methods.AddItem("head");
if (Options) methods.AddItem("options");
if (Patch) methods.AddItem("patch");
if (Post) methods.AddItem("post");
if (Put) methods.AddItem("put");
if (Trace) methods.AddItem("trace");
var json = Json.NewObject();
json.SetProperty("path", Path);
json.SetProperty("controller", Controller.FullName);
json.SetProperty("function", Method.Name);
json.SetProperty("return", Return.FullName);
json.SetProperty("parameters", ps);
json.SetProperty("methods", methods);
return json;
}
#region Enumerate
internal static RouteItem[] Parse(IEnumerable<Assembly> assemblies, bool withVoid)
{
if (assemblies.IsEmpty()) assemblies = AppDomain.CurrentDomain.GetAssemblies();
var baseType = typeof(ApiController);
var items = new ArrayBuilder<RouteItem>();
foreach (var assembly in assemblies)
{
var types = assembly.GetExportedTypes();
foreach (var type in types)
{
if (type.IsNotPublic) continue;
if (!type.IsClass) continue;
if (!RuntimeUtility.IsInherits(type, baseType)) continue;
if (type.Name == "AccountController")
{
}
var pa = RuntimeUtility.GetAttribute<RoutePrefixAttribute>(type, false);
var prefix = (pa == null || pa.Path.IsEmpty()) ? null : pa.Path.Split('/');
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in methods)
{
if (method.IsConstructor) continue;
if (method.IsGenericMethod) continue;
if (!withVoid)
{
var returnType = method.ReturnType;
if (returnType == null || returnType.Equals(typeof(void))) continue;
}
var route = RuntimeUtility.GetAttribute<RouteAttribute>(method);
if (route == null) continue;
var path = route.Path;
if (path.IsEmpty()) path = method.Name;
if (path.IsEmpty()) continue;
path = Concat(prefix, path.Split('/'));
var item = new RouteItem();
item.Controller = type;
item.Method = method;
item.MethodName = method.Name;
item.Parameters = method.GetParameters();
item.Return = method.ReturnType;
item.Path = path;
item.Lower = path.Lower();
item.Get = RuntimeUtility.Contains<HttpGetAttribute>(method);
item.Post = RuntimeUtility.Contains<HttpPostAttribute>(method);
item.Connect = RuntimeUtility.Contains<HttpConnectAttribute>(method);
item.Delete = RuntimeUtility.Contains<HttpDeleteAttribute>(method);
item.Head = RuntimeUtility.Contains<HttpHeadAttribute>(method);
item.Options = RuntimeUtility.Contains<HttpOptionsAttribute>(method);
item.Patch = RuntimeUtility.Contains<HttpPatchAttribute>(method);
item.Put = RuntimeUtility.Contains<HttpPutAttribute>(method);
item.Trace = RuntimeUtility.Contains<HttpTraceAttribute>(method);
items.Add(item);
}
}
}
return items.Export();
}
internal static RouteItem Match(RouteItem[] routes, string path, HttpMethod method)
{
if (routes == null) return null;
if (path.IsEmpty()) path = "/";
var length = routes.Length;
for (var i = 0; i < length; i++)
{
var route = routes[i];
if (route == null) continue;
if (route.Path != path) continue;
if (method == HttpMethod.GET && route.Get) return route;
if (method == HttpMethod.POST && route.Post) return route;
if (method == HttpMethod.CONNECT && route.Connect) return route;
if (method == HttpMethod.DELETE && route.Delete) return route;
if (method == HttpMethod.HEAD && route.Head) return route;
if (method == HttpMethod.OPTIONS && route.Options) return route;
if (method == HttpMethod.PATCH && route.Patch) return route;
if (method == HttpMethod.PUT && route.Put) return route;
if (method == HttpMethod.TRACE && route.Trace) return route;
}
var lower = path.Lower();
for (var i = 0; i < length; i++)
{
var route = routes[i];
if (route == null) continue;
if (route.Lower != lower) continue;
if (method == HttpMethod.GET && route.Get) return route;
if (method == HttpMethod.POST && route.Post) return route;
if (method == HttpMethod.CONNECT && route.Connect) return route;
if (method == HttpMethod.DELETE && route.Delete) return route;
if (method == HttpMethod.HEAD && route.Head) return route;
if (method == HttpMethod.OPTIONS && route.Options) return route;
if (method == HttpMethod.PATCH && route.Patch) return route;
if (method == HttpMethod.PUT && route.Put) return route;
if (method == HttpMethod.TRACE && route.Trace) return route;
}
return null;
}
static string Concat(string[] prefix, string[] path)
{
var all = new List<string>(16);
if (prefix != null) all.AddRange(prefix);
if (path != null) all.AddRange(path);
var segs = new List<string>(all.Count);
foreach (var seg in all)
{
if (seg.IsEmpty()) continue;
segs.Add(seg);
}
if (segs.Count < 1) return "/";
return "/" + TextUtility.Join("/", segs.ToArray());
}
#endregion
}
}