DocGenerator.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. using VCommon.Json;
  7. using VCommon.Reflection;
  8. using VCommon.VApplication.Authorization;
  9. namespace VCommon.VOpenApi.Docgen
  10. {
  11. public static class DocGenerator
  12. {
  13. public static string Generate(string name, string version, string basePath, IEnumerable<ApiBind> binds)
  14. {
  15. var doc = new SwaggerDocument
  16. {
  17. info = new Info
  18. {
  19. title = name,
  20. version = version,
  21. },
  22. basePath = basePath,
  23. schemes = new[] { "http" },
  24. host = "",
  25. paths = new Dictionary<string, PathItem>(),
  26. };
  27. var modelsToGenerateDefine = new HashSet<Type>();
  28. //生成paths,并收集入参/返参模型
  29. foreach (var bind in binds)
  30. {
  31. var hasReturnModel = bind.ApiMethod.ReturnType != typeof(void);
  32. if (hasReturnModel) modelsToGenerateDefine.Add(bind.ApiMethod.ReturnType);
  33. var docEntry = doc.paths[bind.RawRoute] = new PathItem();
  34. docEntry.post = new Operation
  35. {
  36. tags = new List<string> { bind.ResourceName },
  37. parameters = new List<Parameter>(),
  38. responses = new Dictionary<string, Response>
  39. {
  40. {
  41. "200", new Response
  42. {
  43. description = "OK",
  44. schema = hasReturnModel
  45. ? new Schema {@ref = "#/definitions/" + bind.ApiMethod.ReturnType.GetFriendlyTypeName()}
  46. : null
  47. }
  48. }
  49. ,
  50. {
  51. "400",new Response
  52. {
  53. description ="Argument error"
  54. }
  55. }
  56. }
  57. };
  58. var authAttrOnType = bind.ApiMethod.DeclaringType.GetCustomAttributeIncludeInterface<VServiceAuthorizeAttribute>();
  59. if (0 != authAttrOnType.Length || bind.ApiMethod.IsDefined(typeof(VServiceAuthorizeAttribute), true))
  60. {
  61. docEntry.post.responses.Add("401", new Response { description = "Authorization required" });
  62. docEntry.post.responses.Add("403", new Response { description = "Access denied" });
  63. docEntry.post.parameters.Add(new Parameter
  64. {
  65. @in = "header",
  66. name = "Authorization",
  67. schema = new Schema { type = "string" }
  68. });
  69. string[] clsPermission = null;
  70. string[] metPermission = null;
  71. if (0 != authAttrOnType.Length) clsPermission = authAttrOnType.SelectMany(p => p.AnyPermissionsRequired).ToArray();
  72. if (bind.ApiMethod.IsDefined(typeof(VServiceAuthorizeAttribute), true)) metPermission = bind.ApiMethod.GetCustomAttributes<VServiceAuthorizeAttribute>().SelectMany(p => p.AnyPermissionsRequired).ToArray();
  73. var sb = new StringBuilder();
  74. if (0 < clsPermission?.Length || 0 < metPermission?.Length)
  75. {
  76. sb.AppendLine("Permission required:");
  77. if (0 < clsPermission?.Length && 0 < metPermission?.Length)
  78. {
  79. sb.AppendLine("A:" + string.Join(",", clsPermission));
  80. sb.AppendLine("B:" + string.Join(",", metPermission));
  81. }
  82. else
  83. {
  84. if (0 < clsPermission?.Length) sb.AppendLine(string.Join(",", clsPermission));
  85. if (0 < metPermission?.Length) sb.AppendLine(string.Join(",", metPermission));
  86. }
  87. }
  88. docEntry.post.description = sb.ToString();
  89. }
  90. var inputParamType = bind.InputParamType;
  91. if (null != inputParamType)
  92. {
  93. modelsToGenerateDefine.Add(inputParamType);
  94. docEntry.post.parameters.Add(new Parameter
  95. {
  96. name = "input",
  97. @in = "body",
  98. required = true,
  99. schema = new Schema
  100. {
  101. @ref = "#/definitions/" + inputParamType.GetFriendlyTypeName()
  102. }
  103. });
  104. }
  105. }
  106. //生成模型定义
  107. doc.definitions = SchemaCrawler.Crawl(modelsToGenerateDefine);
  108. return VJsonSerializer.Serialize(doc);
  109. }
  110. }
  111. }