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

4 years ago
3 years ago
4 years ago
  1. using Apewer.Network;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace Apewer.AspNetBridge
  7. {
  8. [Serializable]
  9. internal class RouteItem : IToJson
  10. {
  11. public string Path;
  12. public string Lower;
  13. public Type Controller;
  14. public MethodInfo Method;
  15. public string MethodName;
  16. public bool Connect;
  17. public bool Delete;
  18. public bool Get;
  19. public bool Head;
  20. public bool Options;
  21. public bool Patch;
  22. public bool Post;
  23. public bool Put;
  24. public bool Trace;
  25. public ParameterInfo[] Parameters;
  26. public Type Return;
  27. public Json ToJson()
  28. {
  29. var ps = Json.NewObject();
  30. foreach (var parameter in Parameters) ps.SetProperty(parameter.Name, parameter.ParameterType.FullName);
  31. var methods = Json.NewArray();
  32. if (Connect) methods.AddItem("connect");
  33. if (Delete) methods.AddItem("delete");
  34. if (Get) methods.AddItem("get");
  35. if (Head) methods.AddItem("head");
  36. if (Options) methods.AddItem("options");
  37. if (Patch) methods.AddItem("patch");
  38. if (Post) methods.AddItem("post");
  39. if (Put) methods.AddItem("put");
  40. if (Trace) methods.AddItem("trace");
  41. var json = Json.NewObject();
  42. json.SetProperty("path", Path);
  43. json.SetProperty("controller", Controller.FullName);
  44. json.SetProperty("function", Method.Name);
  45. json.SetProperty("return", Return.FullName);
  46. json.SetProperty("parameters", ps);
  47. json.SetProperty("methods", methods);
  48. return json;
  49. }
  50. #region Enumerate
  51. internal static RouteItem[] Parse(IEnumerable<Assembly> assemblies, bool withVoid)
  52. {
  53. if (assemblies.IsEmpty()) assemblies = AppDomain.CurrentDomain.GetAssemblies();
  54. var baseType = typeof(ApiController);
  55. var items = new ArrayBuilder<RouteItem>();
  56. foreach (var assembly in assemblies)
  57. {
  58. var types = assembly.GetExportedTypes();
  59. foreach (var type in types)
  60. {
  61. if (type.IsNotPublic) continue;
  62. if (!type.IsClass) continue;
  63. if (!RuntimeUtility.IsInherits(type, baseType)) continue;
  64. if (type.Name == "AccountController")
  65. {
  66. }
  67. var pa = RuntimeUtility.GetAttribute<RoutePrefixAttribute>(type, false);
  68. var prefix = (pa == null || pa.Path.IsEmpty()) ? null : pa.Path.Split('/');
  69. var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
  70. foreach (var method in methods)
  71. {
  72. if (method.IsConstructor) continue;
  73. if (method.IsGenericMethod) continue;
  74. if (!withVoid)
  75. {
  76. var returnType = method.ReturnType;
  77. if (returnType == null || returnType.Equals(typeof(void))) continue;
  78. }
  79. var route = RuntimeUtility.GetAttribute<RouteAttribute>(method);
  80. if (route == null) continue;
  81. var path = route.Path;
  82. if (path.IsEmpty()) path = method.Name;
  83. if (path.IsEmpty()) continue;
  84. path = Concat(prefix, path.Split('/'));
  85. var item = new RouteItem();
  86. item.Controller = type;
  87. item.Method = method;
  88. item.MethodName = method.Name;
  89. item.Parameters = method.GetParameters();
  90. item.Return = method.ReturnType;
  91. item.Path = path;
  92. item.Lower = path.Lower();
  93. item.Get = RuntimeUtility.Contains<HttpGetAttribute>(method);
  94. item.Post = RuntimeUtility.Contains<HttpPostAttribute>(method);
  95. item.Connect = RuntimeUtility.Contains<HttpConnectAttribute>(method);
  96. item.Delete = RuntimeUtility.Contains<HttpDeleteAttribute>(method);
  97. item.Head = RuntimeUtility.Contains<HttpHeadAttribute>(method);
  98. item.Options = RuntimeUtility.Contains<HttpOptionsAttribute>(method);
  99. item.Patch = RuntimeUtility.Contains<HttpPatchAttribute>(method);
  100. item.Put = RuntimeUtility.Contains<HttpPutAttribute>(method);
  101. item.Trace = RuntimeUtility.Contains<HttpTraceAttribute>(method);
  102. items.Add(item);
  103. }
  104. }
  105. }
  106. return items.Export();
  107. }
  108. internal static RouteItem Match(RouteItem[] routes, string path, HttpMethod method)
  109. {
  110. if (routes == null) return null;
  111. if (path.IsEmpty()) path = "/";
  112. var length = routes.Length;
  113. for (var i = 0; i < length; i++)
  114. {
  115. var route = routes[i];
  116. if (route == null) continue;
  117. if (route.Path != path) continue;
  118. if (method == HttpMethod.GET && route.Get) return route;
  119. if (method == HttpMethod.POST && route.Post) return route;
  120. if (method == HttpMethod.CONNECT && route.Connect) return route;
  121. if (method == HttpMethod.DELETE && route.Delete) return route;
  122. if (method == HttpMethod.HEAD && route.Head) return route;
  123. if (method == HttpMethod.OPTIONS && route.Options) return route;
  124. if (method == HttpMethod.PATCH && route.Patch) return route;
  125. if (method == HttpMethod.PUT && route.Put) return route;
  126. if (method == HttpMethod.TRACE && route.Trace) return route;
  127. }
  128. var lower = path.Lower();
  129. for (var i = 0; i < length; i++)
  130. {
  131. var route = routes[i];
  132. if (route == null) continue;
  133. if (route.Lower != lower) continue;
  134. if (method == HttpMethod.GET && route.Get) return route;
  135. if (method == HttpMethod.POST && route.Post) return route;
  136. if (method == HttpMethod.CONNECT && route.Connect) return route;
  137. if (method == HttpMethod.DELETE && route.Delete) return route;
  138. if (method == HttpMethod.HEAD && route.Head) return route;
  139. if (method == HttpMethod.OPTIONS && route.Options) return route;
  140. if (method == HttpMethod.PATCH && route.Patch) return route;
  141. if (method == HttpMethod.PUT && route.Put) return route;
  142. if (method == HttpMethod.TRACE && route.Trace) return route;
  143. }
  144. return null;
  145. }
  146. static string Concat(string[] prefix, string[] path)
  147. {
  148. var all = new List<string>(16);
  149. if (prefix != null) all.AddRange(prefix);
  150. if (path != null) all.AddRange(path);
  151. var segs = new List<string>(all.Count);
  152. foreach (var seg in all)
  153. {
  154. if (seg.IsEmpty()) continue;
  155. segs.Add(seg);
  156. }
  157. if (segs.Count < 1) return "/";
  158. return "/" + TextUtility.Join("/", segs.ToArray());
  159. }
  160. #endregion
  161. }
  162. }