近期一直在学习asp.net core,微软的文档太难看,都是英文翻译过来的,很不友好,感谢这个博客,从壹开始前后端分离【 .net core2.0 +vue2.0 】,让我入门了,刚学到这个swagger时,我就有个需求,因为我之前写过的系统是分了不同的模块,模块里面再分控制器,不同模块经常会有相同名称的控制器,例如销售中心模块里有个合同管理控制器,采购中心模块里也有个合同管理控制器,而且我一个系统接口可能得上百个,那如果都在一个页面显示的话,那也太多了,所以我想能不能把接口进行分组。

在博客系统后面也有介绍到swagger:api多版本控制,带来的思考,还有网上查到的【dotnet core】swagger下简单的给webapi分组(我发现网上关于asp.net core的资料还是比较少),再结合我自己的需求修改了一下。

先说下我的想法:

定义一个系统分组枚举enum,包含我系统所有的控制器分组(或者版本),然后再定义一个特性attribute,可以接收刚才那个enum值,在需要分组的控制器类上面定义特性attribute,swagger根据系统分组枚举enum的值进行分组,将特性attribute的分组枚举值一样的归为同一个分组,没有加特性attribute的归在无分组下,最终效果如下

 

 

下面是我的代码,理解为主,不用完全按我写的

基础swagger的用法就不说的,具体可看 从壹开始前后端分离【 .net core2.0 +vue2.0 】这个大师关于swagger部分的教程,非常适合初级入门

在项目创建一个目录(apigroup),然后创建三个类,分别为apigroupattribute.cs(控制器特性),apigroupnames.css(系统分组枚举),groupinfoattribute.cs(给系统分组枚举值增加相关信息的特性,这个主要是用于在swagger分组时可关联title,version,description值)

 

 apigroupattribute.cs代码如下

using microsoft.aspnetcore.mvc.apiexplorer;
using system;
using system.collections.generic;
using system.linq;
using system.threading.tasks;

namespace itsys.apigroup
{
    /// <summary>
    /// 系统分组特性
    /// </summary>
    public class apigroupattribute : attribute, iapidescriptiongroupnameprovider
    {
        public apigroupattribute(apigroupnames name)
        {
            groupname = name.tostring();
        }
        public string groupname { get; set; }
    }
}

 apigroupnames.cs代码如下

using system;
using system.collections.generic;
using system.linq;
using system.threading.tasks;

namespace itsys.apigroup
{
    /// <summary>
    /// 系统分组枚举值
    /// </summary>
    public enum apigroupnames
    {
        [groupinfo(title ="登录认证",description ="登录认证相关接口",version ="v1")]
        auth,
        [groupinfo(title = "it", description = "登录认证相关接口")]
        it,
        [groupinfo(title = "人力资源", description = "登录认证相关接口")]
        hr,
        cw
    }
}

groupinfoattribute.cs代码如下

using system;
using system.collections.generic;
using system.linq;
using system.threading.tasks;

namespace itsys.apigroup
{
    /// <summary>
    /// 系统模块枚举注释
    /// </summary>
    public class groupinfoattribute : attribute
    {
        public string title { get; set; }
        public string version { get; set; }
        public string description { get; set; }
    }
}

 

打开startup.cs文件修改configureservices方法(为了方便查看,只列出关于swagger分组的关键代码)

public void configureservices(iservicecollection services)
{
    
    #region swagger
    services.addswaggergen(options =>
    {
        //遍历apigroupnames所有枚举值生成接口文档,skip(1)是因为enum第一个fieldinfo是内置的一个int值
        typeof(apigroupnames).getfields().skip(1).tolist().foreach(f =>
        {
            //获取枚举值上的特性
            var info = f.getcustomattributes(typeof(groupinfoattribute), false).oftype<groupinfoattribute>().firstordefault();
            options.swaggerdoc(f.name, new swashbuckle.aspnetcore.swagger.info
            {
                title = info?.title,
                version = info?.version,
                description = info?.description
            });
        });
        //没有加特性的分到这个nogroup上
        options.swaggerdoc("nogroup", new swashbuckle.aspnetcore.swagger.info
        {
            title = "无分组"
        });
        //判断接口归于哪个分组
        options.docinclusionpredicate((docname, apidescription) =>
        {
            if (docname == "nogroup")
            {
                //当分组为nogroup时,只要没加特性的都属于这个组
                return string.isnullorempty(apidescription.groupname);
            }
            else
            {
                return apidescription.groupname == docname;
            }
        });
}

修改configure方法

public void configure(iapplicationbuilder app, ihostingenvironment env)
{

    #region swagger
    app.useswagger();
    app.useswaggerui(options =>
    {
        //遍历apigroupnames所有枚举值生成接口文档,skip(1)是因为enum第一个fieldinfo是内置的一个int值
        typeof(apigroupnames).getfields().skip(1).tolist().foreach(f =>
        {
            //获取枚举值上的特性
            var info = f.getcustomattributes(typeof(groupinfoattribute), false).oftype<groupinfoattribute>().firstordefault();
            options.swaggerendpoint($"/swagger/{f.name}/swagger.json", info != null ? info.title : f.name);

        });
        options.swaggerendpoint("/swagger/nogroup/swagger.json", "无分组");
    });
    #endregion
}

然后你f6生成一下,没出错的话,就ctrl+f5看看,正常的话就会在swagger右上角看到分组了。

 

 在你需要进行分组的控制器上加上这个分组就ok了

 

目前是一个接口只归为一个分组,但可能实际中有些公用接口,会出现在多个分组模块里的,那可以将apigroupattribute增加一个string[]或apigroupnames[]属性,接收多个枚举值,或者定义多个apigroupattribute特性,不过在configureservices里的swagger的docinclusionpredicate分组过滤方法里,就不能单判断groupname参数了,可以利用参数apidescription反射得出接口控制器上的apigroupattribute特性,获取所有的apigroupnames枚举值,再进行判断,实现一个接口可以归为多个分组。