kazelee
2025-05-21 5ad394cf1708a4629f90f40bfd9b48d9a9f6f0c8
App_Start/SwaggerControllerDescProvider.cs
@@ -80,158 +80,4 @@
            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;
                        }
                    }
                }
            }
        }
    }
}