十年河东,十年河西,莫欺少年穷

学无止境,精益求精

net6集成了swagger的基础功能,但功能不够用

因此只能自定义扩展方法了,如下

1、集成Jwt授权

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_System

 

 

 将

builder.Services.AddSwaggerGen();

改成

builder.Services.AddSwaggerGen(c =>
{
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header. \r\nExample: 'Bearer abcdefxxx'",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Authorization"
},
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});

2、增加Swagger注释

增加swagger注释后,测试人员/前段开发人员就可以自己看文档了,省的在开发人员面前叽叽歪歪

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_System_02

2.1、设置Model层和Api层项目XML输出

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_xml_03

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_System_04

 

 

 代码如下:

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_Text_05

builder.Services.AddSwaggerGen(c =>
{
var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);
//c.IncludeXmlComments(Path.Combine(basePath, Assembly.GetExecutingAssembly().GetName().Name+".xml"), true);
c.IncludeXmlComments(Path.Combine(basePath, "swap.xml"), true);
c.IncludeXmlComments(Path.Combine(basePath, "swapModels.xml"), true);

//
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Authorization"
},
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});

View Code

3、自定义属性隐藏及Api方法隐藏

3.1、Api层新建swagger过滤器

using Microsoft.OpenApi.Models;
using swapCommon;//HiddenFieldAttribute 和 HiddenAttribute 在公共类库存
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;

namespace swapInit
{
public class HiddenApiFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var item in context.ApiDescriptions)
{
if (item.TryGetMethodInfo(out MethodInfo methodInfo))
{
if (methodInfo.ReflectedType.CustomAttributes.Any(t => t.AttributeType == typeof(HiddenAttribute))
|| methodInfo.CustomAttributes.Any(t => t.AttributeType == typeof(HiddenAttribute)))
{
var key = "/" + item.RelativePath.TrimEnd('/');
if (key.Contains("?"))
{
int idx = key.IndexOf("?", StringComparison.Ordinal);
key = key.Substring(0, idx);
}
if (swaggerDoc.Paths.ContainsKey(key))
{
swaggerDoc.Paths.Remove(key);
}
}
}
}
}
}


public class HiddenFieldFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var name = context.Type.FullName;
var excludedProperties = context.Type.GetProperties();
foreach (var property in excludedProperties)
{
var attribute = property.GetCustomAttribute<HiddenFieldAttribute>();
if (attribute != null
&& schema.Properties.ContainsKey(ToLowerStart(property.Name)))
{
schema.Properties.Remove(ToLowerStart(property.Name));
}
};
}
public static string ToLowerStart( string source)
{
if (string.IsNullOrWhiteSpace(source))
{
return source;
}
var start = source.Substring(0, 1);
return $"{start.ToLower()}{source.Substring(1, source.Length - 1)}";
}
}
}

View Code

3.2、公共类库层新建属性类

using System;
using System.Collections.Generic;
using System.Text;

namespace swapCommon
{
[AttributeUsage(AttributeTargets.Property)]
public class HiddenFieldAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class HiddenAttribute : Attribute
{
}
}

3.3、引用上述过滤器

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_System_06

builder.Services.AddSwaggerGen(c =>
{
var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);
//c.IncludeXmlComments(Path.Combine(basePath, Assembly.GetExecutingAssembly().GetName().Name+".xml"), true);
c.IncludeXmlComments(Path.Combine(basePath, "swap.xml"), true);
c.IncludeXmlComments(Path.Combine(basePath, "swapModels.xml"), true);
//
c.DocumentFilter<HiddenApiFilter>();
c.SchemaFilter<HiddenFieldFilter>();
//
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Authorization"
},
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});

View Code

3.4、测试Swagger过滤器

3.4.1、定义一个Post方法

/// <summary>
/// 演示字段隐藏
/// </summary>
/// <param name="stdto"></param>
/// <returns></returns>
[HttpPost]
[Route("GetStdto")]
public IActionResult GetStdto([FromBody]stdto stdto)
{
var dt = DateTime.Now;
return Ok(dt );
}

3.4.2、定义参数实体

有了身份证号,可以自动计算出年龄等场景,总之不想让测试和前端人员看到,省的他们叽叽歪歪

public class stdto
{
public string name { get; set; }
public string IdCard { get; set; }
/// <summary>
/// 该字段会在swagger中隐藏
/// </summary>
[HiddenField]
public int age { get; set; }
}

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_Text_07

 

 

 3.5、[Hidden]隐藏 Action 方法

不想让测试或前端在swagger上看到某方法,那就隐藏,省的他们叽叽歪歪

/// <summary>
/// 演示Api隐藏 ,该方法不会展示在swagger上
/// </summary>
/// <param name="Hs">https://www.cn.com/catcher1994/p/responsecaching.html</param>
/// <returns></returns>
[HttpGet]
[Hidden]
[Route("GetTime")]
public IActionResult GetTime()
{
var dt = DateTime.Now;
return Ok(dt);
}

不作截图演示了。

4、规定项目时间返回格式

严格来说这个和swagger没关,但...分享是一种美德

4.1、公共类库层先建JsonResult格式化类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace swapCommon.Ext
{
public class JsonOptionsExt : JsonConverter<DateTime>
{
private readonly string Format;
public JsonOptionsExt(string format = "yyyy-MM-dd HH:mm:ss")
{
Format = format;
}
public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options)
{
writer.WriteStringValue(date.ToString(Format));
}
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// 获取时间类型的字符串
var dt = reader.GetString();
if (!string.IsNullOrEmpty(dt))
{
//将日期与时间之间的"T"替换为一个空格,将结尾的"Z"去掉,否则会报错
dt = dt.Replace("T", " ").Replace("Z", "");
//取到秒,毫秒内容也要去掉,经过测试,不去掉会报错
if (dt.Length > 19)
{
dt = dt.Substring(0, 19);
}
return DateTime.ParseExact(dt, Format, null);
}
return DateTime.Now;
}
}
}

View Code

4.2、添加控制器时引用

 

builder.Services.AddControllers()

改成

builder.Services.AddControllers().AddJsonOptions(options =>
{
//时间格式化响应
options.JsonSerializerOptions.Converters.Add(new JsonOptionsExt());
});

改好后,时间的返回就统一了

Net6 扩展你的Swagger,让它变的更强大,更持久(哈哈哈)_System_08

 

 ok,截止到这儿,就over了,希望前端和测试不要骂我。 

@天才卧龙