为swagger增加枚举说明支持

This commit is contained in:
falcon 2022-04-19 10:45:56 +08:00
parent 48c6d1299c
commit baff3035e8
6 changed files with 150 additions and 16 deletions

View File

@ -12,20 +12,18 @@ namespace Falcon.SugarApi.ApiDefinistions
/// </summary> /// </summary>
public class ApiResponseTypeModelProvider : IApplicationModelProvider public class ApiResponseTypeModelProvider : IApplicationModelProvider
{ {
/// <inheritdoc/>
public int Order => 1; public int Order => 1;
public void OnProvidersExecuted(ApplicationModelProviderContext context) /// <inheritdoc/>
{ public void OnProvidersExecuted(ApplicationModelProviderContext context) {
} }
public void OnProvidersExecuting(ApplicationModelProviderContext context) /// <inheritdoc/>
{ public void OnProvidersExecuting(ApplicationModelProviderContext context) {
foreach (ControllerModel controller in context.Result.Controllers) foreach (ControllerModel controller in context.Result.Controllers) {
{ foreach (ActionModel action in controller.Actions) {
foreach (ActionModel action in controller.Actions) if (!isApiAction(action)) {
{
if (!isApiAction(action))
{
continue; continue;
} }
var art = action.ActionMethod.ReturnType; var art = action.ActionMethod.ReturnType;
@ -43,14 +41,11 @@ namespace Falcon.SugarApi.ApiDefinistions
/// </summary> /// </summary>
/// <param name="am">Action模型</param> /// <param name="am">Action模型</param>
/// <returns>是api方法返回true否则false</returns> /// <returns>是api方法返回true否则false</returns>
protected static bool isApiAction(ActionModel am) protected static bool isApiAction(ActionModel am) {
{ if (am.Controller.Attributes.Any(c => c is ApiControllerAttribute)) {
if (am.Controller.Attributes.Any(c => c is ApiControllerAttribute))
{
return true; return true;
} }
if (am.Attributes.Any(c => c is ApiControllerAttribute)) if (am.Attributes.Any(c => c is ApiControllerAttribute)) {
{
return true; return true;
} }
return false; return false;

View File

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="SqlSugarCore" Version="5.0.6.1" /> <PackageReference Include="SqlSugarCore" Version="5.0.6.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net5' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net5' ">

View File

@ -0,0 +1,19 @@
## 使用SwaggerGenOptions.AddXmlEnumEnable方法可以为枚举类型增加matedata说明
```c#
//注册Swagger
services.AddSwaggerGen(c => {
//获取应用程序基础目录
var basePath = AppContext.BaseDirectory;
//指定应用程序说明XML文件
var xmlFile = new string[] { "ggws.Service.xml", "Ggws.Database.xml", "Falcon.SugarApi.xml" };
foreach (var xf in xmlFile) {
var path = Path.Combine(basePath, xf);
//引入文件
c.IncludeXmlComments(path, true);
//为枚举增加说明
c.AddXmlEnumEnable(path);
}
});
```

View File

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Falcon.SugarApi.Swagger
{
/// <summary>
/// SwaggerGenOptions扩展
/// </summary>
public static class SwaggerGenOptionsExtend
{
/// <summary>
/// 增加xml文件枚举说明支持
/// </summary>
/// <param name="options">SwaggerGenOptions选项</param>
/// <param name="xmlPath">XML文件路径</param>
/// <returns>SwaggerGenOptions</returns>
public static SwaggerGenOptions AddXmlEnumEnable(this SwaggerGenOptions options,string xmlPath) {
options.DocumentFilter<SwaggerXmlEnumFilter>(xmlPath);
return options;
}
}
}

View File

@ -0,0 +1,93 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Xml.XPath;
namespace Falcon.SugarApi.Swagger
{
/// <summary>
/// 通过DescriptionAttribute和summary生成枚举说明
/// </summary>
public class SwaggerXmlEnumFilter:IDocumentFilter
{
private readonly XPathNavigator _xmlNavigator;
/// <summary>
/// 存放程序集中的所有枚举类型
/// </summary>
public static List<Type> AllTypes { get; set; } = null;
/// <summary>
/// 通过提供应用程序文档生成枚举说明
/// </summary>
/// <param name="xmlPath"></param>
public SwaggerXmlEnumFilter(string xmlPath) {
_xmlNavigator = new XPathDocument(xmlPath).CreateNavigator();
AllTypes = AllTypes ?? GetEnumTypes();
}
/// <summary>
/// 初始化程序集中所有枚举类型
/// </summary>
public virtual List<Type> GetEnumTypes() {
var types = new List<Type>();
foreach(var ass in AppDomain.CurrentDomain.GetAssemblies()) {
types.AddRange(ass.GetTypes().Where(m => m.IsEnum));
}
return types;
}
/// <summary>
/// 对文档进行初拉力
/// </summary>
/// <param name="swaggerDoc"></param>
/// <param name="context"></param>
public void Apply(OpenApiDocument swaggerDoc,DocumentFilterContext context) {
var enumList = swaggerDoc.Components.Schemas.Where(m => m.Value.Enum != null && m.Value.Enum.Count > 0);
foreach(var item in enumList) {
var key = item.Key;
var property = item.Value;
var itemType = AllTypes.Find(m => m.Name == key);
var list = new List<OpenApiInteger>();
foreach(var val in property.Enum) {
list.Add((OpenApiInteger)val);
}
property.Description += describeEnum(itemType,list);
}
}
private string describeEnum(Type type,List<OpenApiInteger> enums) {
var enumDescriptions = new List<string>();
foreach(var item in enums) {
if(type == null)
continue;
var value = Enum.Parse(type,item.Value.ToString());
var desc = getDescription(type,value);
if(string.IsNullOrEmpty(desc))
enumDescriptions.Add($"{item.Value}:{Enum.GetName(type,value)}; ");
else
enumDescriptions.Add($"{item.Value}:{Enum.GetName(type,value)},{desc}; ");
}
return $"<br/>{Environment.NewLine}{string.Join("<br/>" + Environment.NewLine,enumDescriptions)}";
}
private string getDescription(Type t,object value) {
foreach(var member in t.GetMembers().Where(m => m.Name == t.GetEnumName(value))) {
foreach(var attr in member.GetCustomAttributes<DescriptionAttribute>()) {
return attr.Description;
}
}
var fullName = $"{t.FullName}.{t.GetEnumName(value)}";
var desc = _xmlNavigator.SelectSingleNode($"doc/members/member[@name='F:{fullName}']/summary")?.InnerXml;
return desc ?? string.Empty;
}
}
}

View File

@ -92,6 +92,10 @@ namespace Falcon.SugarApi.XmlSerialize
#endregion #endregion
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 #pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
/// <summary>
/// 释放占用资源
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing) { protected override void Dispose(bool disposing) {
if (disposing) { if (disposing) {
this.BaseWriter.Dispose(); this.BaseWriter.Dispose();