c#版本是framework4.6.2,老版本的swagger没有分组优化

接口多了,放一起加载慢,优化后打开很流畅,按控制器打开

image

 

  优化的代码

[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]

namespace ShiNiu.PlatformApi
{
    public class SwaggerConfig
    {
        public static void Register()
        {
            var thisAssembly = typeof(SwaggerConfig).Assembly;

            // 先获取所有控制器名称
            var controllerNames = GetControllerNames();

            var swaggerDocs = GlobalConfiguration.Configuration
                .EnableSwagger(c =>
                {
                    // ========== 使用 MultipleApiVersions 按控制器分组 ==========
                    c.MultipleApiVersions(
                        (apiDesc, targetApiVersion) =>
                        {
                            var controllerName = apiDesc.ActionDescriptor.ControllerDescriptor.ControllerName;
                            return targetApiVersion == controllerName;
                        },
                        (vc) =>
                        {
                            // 为每个控制器注册一个版本/分组
                            foreach (var name in controllerNames)
                            {
                                vc.Version(name, $"{name} 模块接口");
                            }
                        }
                    );

                    // ========== 配置文案 ==========
                    c.IncludeXmlComments(string.Format("{0}/bin/xxx.XML", System.AppDomain.CurrentDomain.BaseDirectory));
                    c.IncludeXmlComments(string.Format("{0}/bin/xxx.XML", System.AppDomain.CurrentDomain.BaseDirectory));
                    c.IncludeXmlComments(string.Format("{0}/bin/xxx.XML", System.AppDomain.CurrentDomain.BaseDirectory));

                    c.DocumentFilter<HiddenApiFilter>();
                    c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));

                    c.SchemaId(t =>
                    {
                        if (t == null) return System.Guid.NewGuid().ToString("N");

                        string baseName = t.FullName ?? (t.Namespace != null ? t.Namespace + "." + t.Name : t.Name);

                        if (t.IsGenericType)
                        {
                            try
                            {
                                var genericDef = t.GetGenericTypeDefinition();
                                var genericArgs = string.Join("_", t.GetGenericArguments()
                                    .Select(a => (a.FullName ?? a.Name).Replace('.', '_')));
                                var defName = genericDef.FullName ?? (genericDef.Namespace != null ? genericDef.Namespace + "." + genericDef.Name : genericDef.Name);
                                baseName = defName + "_" + genericArgs;
                            }
                            catch
                            {
                                baseName = t.Name;
                            }
                        }

                        return (baseName ?? t.Name).Replace('+', '_').Replace('.', '_');
                    });

                    c.OperationFilter<HttpHeaderFilter>();
                    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                });

            // ========== SwaggerUI 配置 ==========
            if (IsSwaggerUiEnabled())
            {
                swaggerDocs.EnableSwaggerUi(c =>
                {
                    // 通过 DiscoveryPaths 注册所有分组
                    // 注意:需要把 discoveryPaths 设置为包含所有控制器名称
                    // 但由于 SwaggerUiConfig 构造时 discoveryPaths 已经传入了,
                    // 这里通过反射或重新配置的方式处理

                    // 方法:使用 InjectJavaScript 自定义发现路径
                    // 或者直接修改模板参数

                    // 注入自定义 JavaScript 来支持多分组选择
                    c.InjectJavaScript(thisAssembly, "ShiNiu.PlatformApi.Scripts.swaggerui.swagger_lang.js");
                });
            }
        }

        private static List<string> GetControllerNames()
        {
            return AppDomain.CurrentDomain.GetAssemblies()
                .Where(a => !a.IsDynamic && !a.GlobalAssemblyCache) // 过滤系统程序集
                .SelectMany(a =>
                {
                    try
                    {
                        return a.GetTypes();
                    }
                    catch
                    {
                        return Type.EmptyTypes;
                    }
                })
                .Where(t => typeof(ApiController).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
                .Select(t => t.Name.EndsWith("Controller") ? t.Name.Replace("Controller", "") : t.Name)
                .Distinct()
                .ToList();
        }

        private static bool IsSwaggerUiEnabled()
        {
#if DEBUG
            return true;
#else
            return false;
#endif
        }
    }

    public class CachingSwaggerProvider : ISwaggerProvider
    {
        private static ConcurrentDictionary<string, SwaggerDocument> _cache =
            new ConcurrentDictionary<string, SwaggerDocument>();

        private readonly ISwaggerProvider _swaggerProvider;

        public CachingSwaggerProvider(ISwaggerProvider swaggerProvider)
        {
            _swaggerProvider = swaggerProvider;
        }

        public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
        {
            var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
            SwaggerDocument srcDoc = null;
            //只读取一次
            if (!_cache.TryGetValue(cacheKey, out srcDoc))
            {
                srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
                //srcDoc.info.description = "jiekoumiaoshu";
                srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
                _cache.TryAdd(cacheKey, srcDoc);
            }
            return srcDoc;
        }

        /// <summary>
        /// 从API文档中读取控制器描述
        /// </summary>
        /// <returns>所有控制器描述</returns>
        public static ConcurrentDictionary<string, string> GetControllerDesc()
        {
            string xmlpath = string.Format("{0}/bin/ShiNiu.PlatformApi.XML", System.AppDomain.CurrentDomain.BaseDirectory);
            ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
            if (File.Exists(xmlpath))
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(xmlpath);
                string type = string.Empty, path = string.Empty, controllerName = string.Empty;

                string[] arrPath;
                int length = -1, cCount = "Controller".Length;
                XmlNode summaryNode = null;
                foreach (XmlNode node in xmldoc.SelectNodes("//member"))
                {
                    type = node.Attributes["name"].Value;
                    if (type.StartsWith("T:"))
                    {
                        //控制器
                        arrPath = type.Split('.');
                        length = arrPath.Length;
                        controllerName = arrPath[length - 1];
                        if (controllerName.EndsWith("Controller"))
                        {
                            //获取控制器注释
                            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;
        }
    }
}

 

posted @ 2026-08-27 09:04  世人皆萌  阅读(4)  评论(0)    收藏  举报