using Swashbuckle.Swagger;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Xml;
|
|
namespace HH.WCS.Mobox3.DSZSH {
|
/// <summary>
|
/// Swagger 显示控制器的描述
|
/// </summary>
|
public class SwaggerCacheProvider : ISwaggerProvider
|
{
|
private readonly ISwaggerProvider _swaggerProvider;
|
private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
|
private readonly string _xmlPath;
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="swaggerProvider"></param>
|
/// <param name="xmlpath">xml文档路径</param>
|
public SwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xmlpath)
|
{
|
_swaggerProvider = swaggerProvider;
|
_xmlPath = xmlpath;
|
}
|
|
public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
|
{
|
var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
|
// 只读取一次
|
if (!_cache.TryGetValue(cacheKey, out SwaggerDocument srcDoc))
|
{
|
srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
|
|
srcDoc.vendorExtensions = new Dictionary<string, object>
|
{
|
{ "ControllerDesc", GetControllerDesc() }
|
};
|
_cache.TryAdd(cacheKey, srcDoc);
|
}
|
return srcDoc;
|
}
|
|
/// <summary>
|
/// 从API文档中读取控制器描述
|
/// </summary>
|
/// <returns>所有控制器描述</returns>
|
public ConcurrentDictionary<string, string> GetControllerDesc()
|
{
|
ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
|
if (File.Exists(_xmlPath))
|
{
|
XmlDocument xmldoc = new XmlDocument();
|
xmldoc.Load(_xmlPath);
|
|
string[] arrPath;
|
int cCount = "Controller".Length;
|
foreach (XmlNode node in xmldoc.SelectNodes("//member"))
|
{
|
string type = node.Attributes["name"].Value;
|
if (type.StartsWith("T:"))
|
{
|
arrPath = type.Split('.');
|
string controllerName = arrPath[arrPath.Length - 1];
|
if (controllerName.EndsWith("Controller")) // 控制器
|
{
|
// 获取控制器注释
|
XmlNode summaryNode = node.SelectSingleNode("summary");
|
string key = controllerName.Remove(controllerName.Length - cCount, cCount);
|
if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
|
{
|
controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
|
}
|
}
|
}
|
}
|
}
|
return controllerDescDict;
|
}
|
}
|
|
/// <summary>
|
/// 增强版Swagger提供程序,支持显示控制器和模型的完整文档注释
|
/// </summary>
|
public class EnhancedSwaggerCacheProvider : ISwaggerProvider {
|
private readonly ISwaggerProvider _swaggerProvider;
|
private static readonly ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
|
private readonly string _xmlPath;
|
|
public EnhancedSwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xmlpath) {
|
_swaggerProvider = swaggerProvider;
|
_xmlPath = xmlpath;
|
}
|
|
public SwaggerDocument GetSwagger(string rootUrl, string apiVersion) {
|
var cacheKey = $"{rootUrl}_{apiVersion}";
|
|
return _cache.GetOrAdd(cacheKey, _ =>
|
{
|
var srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
|
|
// 添加控制器描述
|
var (controllerDesc, modelDesc) = GetXmlComments();
|
|
srcDoc.vendorExtensions = new Dictionary<string, object>
|
{
|
{ "ControllerDesc", controllerDesc },
|
{ "ModelDesc", modelDesc }
|
};
|
|
// 为模型添加描述
|
EnhanceModelDescriptions(srcDoc, modelDesc);
|
|
return srcDoc;
|
});
|
}
|
|
/// <summary>
|
/// 从XML文档中提取控制器和模型描述
|
/// </summary>
|
private (ConcurrentDictionary<string, string> controllerDesc,
|
ConcurrentDictionary<string, string> modelDesc) GetXmlComments() {
|
var controllerDesc = new ConcurrentDictionary<string, string>();
|
var modelDesc = new ConcurrentDictionary<string, string>();
|
|
if (!File.Exists(_xmlPath)) return (controllerDesc, modelDesc);
|
|
var xmldoc = new XmlDocument();
|
xmldoc.Load(_xmlPath);
|
|
foreach (XmlNode node in xmldoc.SelectNodes("//member")) {
|
var type = node.Attributes?["name"]?.Value;
|
if (string.IsNullOrEmpty(type)) continue;
|
|
if (type.StartsWith("T:")) {
|
var arrPath = type.Split('.');
|
var typeName = arrPath[arrPath.Length - 1]; // 获取最后一部分
|
|
// 处理控制器
|
if (typeName.EndsWith("Controller")) {
|
var summaryNode = node.SelectSingleNode("summary");
|
if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) {
|
//var key = typeName[..^"Controller".Length];
|
|
string key = typeName;
|
const string controllerSuffix = "Controller";
|
if (typeName.EndsWith(controllerSuffix)) {
|
key = typeName.Substring(0, typeName.Length - controllerSuffix.Length);
|
}
|
|
controllerDesc.TryAdd(key, summaryNode.InnerText.Trim());
|
}
|
}
|
// 处理模型类
|
else if (IsModelType(node)) {
|
var summaryNode = node.SelectSingleNode("summary");
|
if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) {
|
modelDesc.TryAdd(typeName, summaryNode.InnerText.Trim());
|
}
|
|
// 处理模型属性
|
EnhancePropertyDescriptions(node, modelDesc);
|
}
|
}
|
|
}
|
|
return (controllerDesc, modelDesc);
|
}
|
|
/// <summary>
|
/// 判断是否为模型类型
|
/// </summary>
|
private bool IsModelType(XmlNode node) {
|
// 这里可以根据实际需求调整判断逻辑
|
// 例如:排除Controller、排除特定命名空间等
|
var type = node.Attributes?["name"]?.Value ?? "";
|
return type.StartsWith("T:") &&
|
!type.EndsWith("Controller") &&
|
!type.Contains(".Controllers.") &&
|
!type.Contains(".Infrastructure.");
|
}
|
|
/// <summary>
|
/// 增强模型属性的描述
|
/// </summary>
|
private void EnhancePropertyDescriptions(XmlNode typeNode, ConcurrentDictionary<string, string> modelDesc) {
|
var typeName = typeNode.Attributes?["name"]?.Value?.Split('.')?.LastOrDefault()?.Substring(2);
|
if (string.IsNullOrEmpty(typeName)) return;
|
|
foreach (XmlNode propNode in typeNode.SelectNodes("field|property")) {
|
var propName = propNode.Attributes?["name"]?.Value;
|
if (string.IsNullOrEmpty(propName)) continue;
|
|
var summaryNode = propNode.SelectSingleNode("summary");
|
var exampleNode = propNode.SelectSingleNode("example");
|
|
if (summaryNode != null && !string.IsNullOrWhiteSpace(summaryNode.InnerText)) {
|
var fullPropKey = $"{typeName}.{propName}";
|
var description = summaryNode.InnerText.Trim();
|
|
if (exampleNode != null && !string.IsNullOrWhiteSpace(exampleNode.InnerText)) {
|
description += $"\n\n示例: {exampleNode.InnerText.Trim()}";
|
}
|
|
modelDesc.TryAdd(fullPropKey, description);
|
}
|
}
|
}
|
|
/// <summary>
|
/// 增强Swagger文档中的模型描述
|
/// </summary>
|
private void EnhanceModelDescriptions(SwaggerDocument swaggerDoc, ConcurrentDictionary<string, string> modelDesc) {
|
if (swaggerDoc.definitions == null) return;
|
|
foreach (var definition in swaggerDoc.definitions) {
|
// 处理模型类本身描述
|
if (modelDesc.TryGetValue(definition.Key, out var classDesc)) {
|
definition.Value.description = classDesc;
|
}
|
|
// 处理模型属性描述
|
if (definition.Value.properties != null) {
|
foreach (var property in definition.Value.properties) {
|
var fullPropKey = $"{definition.Key}.{property.Key}";
|
if (modelDesc.TryGetValue(fullPropKey, out var propDesc)) {
|
property.Value.description = propDesc;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|