| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |