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.

180 lines
5.8 KiB

4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. namespace Apewer.Web
  5. {
  6. /// <summary></summary>
  7. public sealed class ApiApplication : IToJson
  8. {
  9. #region fields
  10. Type _type = null;
  11. string _module = null;
  12. // ApiAttribute
  13. string _name = null;
  14. string _lower = null;
  15. string _caption = null;
  16. string _description = null;
  17. // invoke & enumerate
  18. bool _independent = false;
  19. bool _hidden = false;
  20. // functions
  21. Dictionary<string, ApiFunction> _dict = new Dictionary<string, ApiFunction>();
  22. List<ApiFunction> _list = new List<ApiFunction>();
  23. #endregion
  24. #region properties
  25. /// <summary></summary>
  26. public Type Type { get => _type; }
  27. /// <summary></summary>
  28. public string Module { get => _module; }
  29. /// <summary></summary>
  30. public string Name { get => _name; }
  31. /// <summary></summary>
  32. public string Caption { get => _caption; }
  33. /// <summary></summary>
  34. public string Description { get => _description; }
  35. /// <summary></summary>
  36. public bool Independent { get => _independent; }
  37. /// <summary></summary>
  38. public bool Hidden { get => _hidden; }
  39. /// <summary></summary>
  40. public ApiFunction[] Functions { get => _list.ToArray(); }
  41. #endregion
  42. /// <summary></summary>
  43. public ApiApplication(Type type, ApiAttribute api)
  44. {
  45. // type
  46. _type = type;
  47. // api
  48. if (api == null)
  49. {
  50. _name = type?.Name;
  51. }
  52. else
  53. {
  54. _name = string.IsNullOrEmpty(api.Name) ? type?.Name : api.Name;
  55. _caption = api.Caption;
  56. _description = api.Description;
  57. }
  58. if (type != null)
  59. {
  60. // caption
  61. if (string.IsNullOrEmpty(_caption))
  62. {
  63. var captions = type.GetCustomAttributes(typeof(CaptionAttribute), true);
  64. if (captions.Length > 0)
  65. {
  66. var caption = (CaptionAttribute)captions[0];
  67. _caption = caption.Title;
  68. if (string.IsNullOrEmpty(_description))
  69. {
  70. _description = caption.Description;
  71. }
  72. }
  73. }
  74. // hidden
  75. if (type.Contains<HiddenAttribute>(false)) _hidden = true;
  76. // independent
  77. if (type.Contains<IndependentAttribute>(false)) _independent = true;
  78. // Module
  79. var assemblyName = type.Assembly.GetName();
  80. _module = TextUtility.Join("-", assemblyName.Name, assemblyName.Version.ToString());
  81. // functions
  82. var funcs = new Dictionary<string, ApiFunction>();
  83. var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
  84. foreach (var method in methods)
  85. {
  86. var func = ApiFunction.Parse(this, method);
  87. if (func == null) continue;
  88. var funcKey = func.Name.Lower();
  89. if (funcs.ContainsKey(funcKey)) continue;
  90. funcs.Add(funcKey, func);
  91. }
  92. _dict = funcs;
  93. _list.AddRange(funcs.Values);
  94. _list.Sort(new Comparison<ApiFunction>((a, b) => a.Name.CompareTo(b.Name)));
  95. }
  96. }
  97. internal ApiFunction GetFunction(string name)
  98. {
  99. if (string.IsNullOrEmpty(name)) return null;
  100. if (_dict.TryGetValue(name.ToLower(), out var func)) return func;
  101. return null;
  102. }
  103. /// <summary></summary>
  104. public Json ToJson() => ToJson(new ApiOptions());
  105. internal Json ToJson(ApiOptions options)
  106. {
  107. if (Hidden) return null;
  108. var json = Json.NewObject();
  109. json.SetProperty("name", _name);
  110. if (!string.IsNullOrEmpty(_caption)) json.SetProperty("caption", _caption);
  111. if (!string.IsNullOrEmpty(_description)) json.SetProperty("description", _description);
  112. if (options != null)
  113. {
  114. if (options.WithTypeName) json.SetProperty("type", _type.FullName);
  115. if (options.WithModuleName) json.SetProperty("mudule", _module);
  116. if (options.AllowEnumerate) json.SetProperty("functions", Json.From(_list));
  117. }
  118. return json;
  119. }
  120. /// <summary>解析类型,获取 <see cref="ApiApplication"/> 实例。</summary>
  121. /// <param name="type">要解析的类型。</param>
  122. /// <param name="requireAttribute">要求此类型拥有 Api 特性。</param>
  123. /// <returns>解析成功返回实例,解析失败返回 NULL 值。</returns>
  124. public static ApiApplication Parse(Type type, bool requireAttribute)
  125. {
  126. if (type == null) return null;
  127. // 检查类型的属性。
  128. if (!type.IsClass) return null;
  129. if (type.IsAbstract) return null;
  130. if (type.IsGenericType) return null;
  131. if (type.GetGenericArguments().NotEmpty()) return null;
  132. if (!RuntimeUtility.CanNew(type)) return null;
  133. // 判断基类。
  134. if (!typeof(ApiController).IsAssignableFrom(type)) return null;
  135. // 检查类型的特性。
  136. var apis = type.GetCustomAttributes(typeof(ApiAttribute), false);
  137. var api = apis.Length > 0 ? (ApiAttribute)apis[0] : null;
  138. if (requireAttribute && api == null) return null;
  139. return new ApiApplication(type, api);
  140. }
  141. }
  142. }