AspNetCore 生成接口文档

获取所有继承自 ControllerBase 的类,获取其公共的实例的方法(不包含父类),认作接口,

接口注释的xml文件,可以在项目-右键属性-生成-XML文档文件勾选,再次生成。

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;

/*
    // Install-Package System.Text.Encoding.CodePages
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    // BackgroundService
    services.AddHostedService<GenerateApiDocumentService>();
     
 */
namespace App.HostServices
{
    /// <summary>
    /// 生成接口文档
    /// </summary>
    public class GenerateApiDocumentService : BackgroundService
    {
        /// <summary>生成的Csv路径</summary>
        public static string CSVPath = "d:/1.csv";
        /// <summary>当前提供的接口生成的注释路径</summary>
        public static string AnnotationXmlPath = "d:/API.xml";


        /// <summary>
        /// 
        /// </summary>
        /// <param name="stoppingToken"></param>
        /// <returns></returns>
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var doc = new XmlDocument();
            doc.Load(AnnotationXmlPath);
            var xpath = "/doc/members/member";
            var nodes = doc.SelectNodes(xpath).Cast<XmlNode>().ToList();

            var ass = Assembly.GetEntryAssembly();
            var types = ass.GetTypes();

            var cbt = typeof(ControllerBase);

            var ls = new List<MM>();
            foreach (var type in types)
            {
                if (!cbt.IsAssignableFrom(type)) continue;

                // 过滤一些
                if (type.FullName.StartsWith("Microsoft.AspNetCore.Mvc")) continue;
                if (type.Name.EqualIgnoreCase("BaseController")) continue;

                var publicMethods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
                if (!publicMethods.Any()) continue;

                foreach (var method in publicMethods)
                {
                    var attrs = method.GetCustomAttributes().ToList();

                    var httpMethod = HttpMethod.Get;
                    if (attrs.Any(d => d.GetType() == typeof(HttpPostAttribute)))
                    {
                        httpMethod = HttpMethod.Post;
                    }

                    var methodParas = new List<String>();
                    // 参数
                    var paras = method.GetParameters();
                    foreach (var para in paras)
                    {
                        methodParas.Add($"{para.ParameterType.Name} {para.Name}");
                    }

                    var summary = getSummary(nodes, type.FullName, method.Name, paras.Length > 0);
                    var mm = new MM()
                    {
                        ControllerName = type.Name,
                        ActionName = method.Name,
                        HttpMethod = httpMethod,
                        Summary = summary,

                        Attrs = attrs.Select(d => d.GetType().Name).ToList(),
                        Paras = methodParas,
                    };

                    ls.Add(mm);
                }

            }

            ToFile(CSVPath, ls);

            await Task.CompletedTask;
        }

        static void ToFile(String path, List<MM> ls)
        {
            File.Delete(path);

            var defEncoding = Encoding.GetEncoding("gb2312");
            using (var fs = File.OpenWrite(path))
            {
                {
                    var headerStr = "ControllerName,ActionName,Summary,Paras,HttpMethod,Attrs\n";
                    var data = defEncoding.GetBytes(headerStr);
                    fs.Write(data);
                }

                foreach (var item in ls)
                {
                    {
                        var rowStr = $"{item.ControllerName},{item.ActionName}," +
                            $"{item.Summary}," +
                            $"{item.Paras.Join(" ")}," +
                            $"{item.HttpMethod},{item.Attrs.Join("/")}\n";
                        var data = defEncoding.GetBytes(rowStr);
                        fs.Write(data);
                    }
                }
            }
        }

        // 获取方法注释
        static String getSummary(IList<XmlNode> nodes, String typeFullName, String methodName, bool hasParas)
        {
            /*
                 <member name="M:System.on(System.String)">
                     <summary>创建新的User</summary>
                     <param name="token"></param>
                     <returns></returns>
                 </member>
            */
            // M:API.Common.TokenSession.CreateSession(
            var name = $"M:{typeFullName}.{methodName}{(hasParas ? "(" : "")}";

            foreach (var node in nodes)
            {
                var attrs = node.Attributes;
                foreach (XmlAttribute attr in attrs)
                {
                    if (attr.Name.EqualIgnoreCase("name"))
                    {
                        var attrVal = attr.Value;
                        if (attrVal.StartsWithIgnoreCase(name))
                        {
                            // 读取 summary
                            var summary = node.ChildNodes.Cast<XmlNode>().FirstOrDefault(d => d.Name.EqualIgnoreCase("summary"));

                            return summary?.InnerText;
                        }
                    }

                }
            }

            return null;
        }

    }

    /// <summary></summary>
    public class MM
    {
        public String ControllerName { get; set; }
        public String ActionName { get; set; }

        public HttpMethod HttpMethod { get; set; }

        /// <summary>注释</summary>
        public String Summary { get; set; }

        public IList<String> Attrs { get; set; }

        public IList<String> Paras { get; set; }

    }


}

  

posted @ 2021-04-26 16:20  我的用户名  阅读(130)  评论(0编辑  收藏  举报