using Microsoft.AspNetCore.Mvc; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Text; namespace Blahblah.FlowerStory.Server.Controller; /// [Route("apidoc")] public class SwaggerController : ControllerBase { private readonly SwaggerGenerator generator; /// public SwaggerController(SwaggerGenerator generator) { this.generator = generator; } /// [Route("get/{version}")] [Produces("text/html")] [HttpGet] [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] public ActionResult GetApi(string version) { var model = generator.GetSwagger(version); var builder = new StringBuilder(); builder.Append($@" Flower Story - API 接口文档

{model.Info.Title}

接口文档 {model.Info.Version}

{model.Info.Description}

"); foreach (var tag in model.Tags) { if (tag == null) { continue; } builder.Append($@"

{tag.Description}

"); foreach (var item in model.Paths) { if (item.Value.Operations != null) { foreach (var operation in item.Value.Operations) { if (!operation.Value.Tags.Any(t => t.Name == tag.Name)) { continue; } var method = operation.Key.ToString(); builder.Append($@"

{operation.Value.Summary}

{method.ToUpper()} {item.Key}
"); if (operation.Value.Parameters?.Count > 0) { builder.Append(@"

请求参数

"); foreach (var param in operation.Value.Parameters) { var required = param.Required ? "*" : string.Empty; builder.Append($@" "); } builder.Append(@"
参数位置类型说明
{required}{param.Name} {param.In} {param.Schema.Type} {param.Description}
"); } if (operation.Value.RequestBody?.Content != null) { foreach (var content in operation.Value.RequestBody.Content) { builder.Append($@"

请求实体 ({content.Key})

"); if (content.Value.Schema.Type == "array") { builder.Append($@" "); } else { IDictionary properties; if (content.Value.Schema.Reference != null && model.Components.Schemas.TryGetValue(content.Value.Schema.Reference.Id, out var schema)) { properties = schema.Properties; } else { properties = content.Value.Schema.Properties; } foreach (var prop in properties) { var required = content.Value.Schema.Required.Contains(prop.Key) ? "*" : string.Empty; var type = prop.Value.Type; if (type == "string" && prop.Value.Format == "binary") { type = "file"; } else if (type == "array") { type = prop.Value.Items.Type; if (type == "string" && prop.Value.Items.Format == "binary") { type = "file"; } type += "[]"; } builder.Append($@" "); } } builder.Append(@"
字段类型说明
. {content.Value.Schema.Items.Type}[] {operation.Value.RequestBody.Description}
{required}{prop.Key} {type} {prop.Value.Description}
"); } } if (operation.Value.Responses?.Count > 0) { builder.Append(@"

响应 HTTP 状态

"); foreach (var response in operation.Value.Responses) { builder.Append($@" "); if (response.Key == "200") { foreach (var content in response.Value.Content) { builder.Append($@" "); } } } builder.Append(@"
状态码说明
{response.Key} {response.Value.Description}

{content.Key}

"); OpenApiSchema schema; if (content.Value.Schema.Type == "array") { schema = content.Value.Schema.Items; builder.Append($@" "); } else { schema = content.Value.Schema; } if (schema.Reference != null && model.Components.Schemas.TryGetValue(schema.Reference.Id, out var s)) { schema = s; } if (schema.Properties.Count > 0) { foreach (var p in schema.Properties) { bool isArray = p.Value.Type == "array"; string type = isArray ? $"{p.Value.Items.Reference?.Id ?? p.Value.Items.Type}[]" : p.Value.Type; builder.Append($@" "); if (isArray && p.Value.Items.Reference != null && model.Components.Schemas.TryGetValue(p.Value.Items.Reference.Id, out s)) { foreach (var p2 in s.Properties) { builder.Append($@" "); } } } } else { builder.Append($@" "); } builder.Append(@"
字段类型说明
.{schema.Reference?.Id ?? schema.Type}[]
{p.Key} {type} {p.Value.Description}
  {p2.Key} {p2.Value.Type} {p2.Value.Description}
. {schema.Type}
"); } } } } builder.Append(@"
"); } builder.Append(@"
"); return Content(builder.ToString(), "text/html"); } }