zoukankan      html  css  js  c++  java
  • 【从零开始搭建自己的.NET Core Api框架】(一)创建项目并集成swagger:1.2 swagger的高级应用

    系列目录

    .  创建项目并集成swagger

      1.1 创建

      1.2 完善

    二. 搭建项目整体架构

    三. 集成轻量级ORM框架——SqlSugar

      3.1 搭建环境

      3.2 实战篇:利用SqlSugar快速实现CRUD

      3.3 生成实体类

    四. 集成JWT授权验证

     


     

     

    前一章我们在项目中初步集成了swagger插件,但是还有一些问题需要解决,所以这一章要做的,就是完善swagger的相关设置。

      1. 设置swagger ui页面为启动页

    在前一章的末尾,我们通过在域名后面输入/swagger后,成功访问到swagger ui页,但是我们发现每次运行项目,都会默认访问api/values这个接口,我想要将启动页设为swagger(或者是你画好的任一个html页),那应该怎么设置呢?

    位置就在Properties下的launchSettings.json文件里,只要将profiles下的launchUrl改成你需要的地址就可以

     

    当然,文件里还有其他一些基本设置,比如端口设置,就不一一说了。

     

      2. 注释问题

    swagger很重要的一个功能,就是将我们接口的注释信息和参数(包括实体类)的注释信息显示到页面上。

    现在我们分别将控制器、函数和参数添加相应的注释(添加方式是在类或函数的上一行敲三下“/”)

     

    F5运行,发现swagger ui上并没有将它们显示出来。那是因为还缺少两步

     2.1项目生成xml注释文件

    右键项目名称=>属性=>生成

    勾选“输出”下面的“生成xml文档文件”,后面填写保存该文档的地址(xml文件的名字可以修改,但是不建议修改保存的路径,然后记住这个地址,待会会用到)

     

    操作完之后,我们会发现错误列表会多出很多黄色的警告,提示“缺少XML注释”。

    这时只需要像之前那样,在类或函数的上面一行添加注释即可。(当然,如果没有强迫症的话,装作没看到也是不影响的~)

    如果我们按照刚才记住的地址去文件夹查看,也能看到对应xml文件。

     2.2启动类中添加swagger服务来读取这个xml文件

    重新编辑Startup.cs,修改ConfigureServices函数:

         /// <summary>
            /// This method gets called by the runtime. Use this method to add services to the container.
            /// </summary>
            /// <param name="services"></param>
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
    
                #region Swagger
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "v1.1.0",
                        Title = "Ray WebAPI",
                        Description = "框架集合",
                        TermsOfService = "None",
                        Contact = new Swashbuckle.AspNetCore.Swagger.Contact { Name = "RayWang", Email = "2271272653@qq.com", Url = "http://www.cnblogs.com/RayWang" }
                    });
                    //添加读取注释服务
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "APIHelp.xml");
                    c.IncludeXmlComments(xmlPath);
                });
                #endregion
            }

    以上两步完成之后,F5运行调试:

     

    我们之前添加的注释就全部都出来了。

    现在是不是突然觉得swagger很有用处了?

    其实到这儿,细心的人都会发现,有一个地方还是没有显示注释,就是控制器的名称(在这个例子里就是values),我们之前在代码里明明也添加了注释,这里却没有显示出来,为什么?

    好,接下来要放我个人私藏的大招了~

    解决办法是:在项目中添加一个文件夹“SwaggerHelp”,在该文件加下添加类“SwaggerDocTag”,这个类的作用是根据控制器的名称向swagger ui额外附加注释,代码如下:

    using Swashbuckle.AspNetCore.Swagger;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace CKPI.SwaggerHelp
    {
        /// <summary>
        /// Swagger注释帮助类
        /// </summary>
        public class SwaggerDocTag : IDocumentFilter
        {
            /// <summary>
            /// 添加附加注释
            /// </summary>
            /// <param name="swaggerDoc"></param>
            /// <param name="context"></param>
            public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
            {
                swaggerDoc.Tags = new List<Tag>
                {
                    //添加对应的控制器描述 这个是我好不容易在issues里面翻到的
                    new Tag { Name = "Values", Description = "测试模块" },
                };
            }
        }
    }

    接下来要去Startup.cs添加相应的服务:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using CKPI.SwaggerHelp;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Microsoft.Extensions.PlatformAbstractions;
    using Swashbuckle.AspNetCore.Swagger;
    
    namespace RayPI
    {
        /// <summary>
        /// 
        /// </summary>
        public class Startup
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="configuration"></param>
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
            /// <summary>
            /// 
            /// </summary>
            public IConfiguration Configuration { get; }
    
            /// <summary>
            /// This method gets called by the runtime. Use this method to add services to the container.
            /// </summary>
            /// <param name="services"></param>
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
    
                #region Swagger
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "v1.1.0",
                        Title = "Ray WebAPI",
                        Description = "框架集合",
                        TermsOfService = "None",
                        Contact = new Swashbuckle.AspNetCore.Swagger.Contact { Name = "RayWang", Email = "2271272653@qq.com", Url = "http://www.cnblogs.com/RayWang" }
                    });
                    //添加注释服务
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "APIHelp.xml");
                    c.IncludeXmlComments(xmlPath);
                    //添加对控制器的标签(描述)
                    c.DocumentFilter<SwaggerDocTag>();
                });
                #endregion
            }
    
            /// <summary>
            /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            /// </summary>
            /// <param name="app"></param>
            /// <param name="env"></param>
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseMvc();
    
                #region Swagger
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
                });
                #endregion
            }
        }
    }

    现在再次运行调试,你会发现,控制器的注释就可以显示了

     

    这儿的“测试模块”的注释,其实是从SwaggerDocTag类中读取出来的,并不是控制器本身的注释。

    然后,这只是我个人目前为止发现的最好好用的方法,如果有人有什么其他更好的解决办法,欢迎大家指教,互相学习~

    BTW,这里提一下可能会遇到的问题:如果项目发布之后,或是上线服务器之后,发现注释又没了,十有八九是生成的xml文件路径的问题。可以按照之前的步骤,依次排查,重新修改路径就可以了。


    【20180705】更新显示控制器注释方法:

    经@陆韦里同学私信指教,现提供另一种swagger展示控制器注释的方法,思路如下:

    其实我们对控制器添加的注释,已经生成在xml注释文档里了(APIHelp.xml),打开xml文档,如下:

    仔细观察下,其实就能找到它的规律:我们需要的主要数据都在二级节点<members>里,三级节点<member>有一个name属性,这个name的值凡是以“T:”开头的表示的都是类,凡是以“M:”开头的表示的都是函数,其中类里面凡是控制器必然会以“Controller”结尾。

    所以我们要写一个读取xml的函数,根据这个规则,将注释提取出来,就可以了。

    Stratup.cs里以前地配置不需要改变,只需要重新编辑SwaggerHelp下面的SwaggerDocTag.cs,添加一个GetControllerDesc函数,SwaggerDocTag.cs的完整代码如下:

    using Microsoft.Extensions.PlatformAbstractions;
    using Swashbuckle.AspNetCore.Swagger;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml;
    
    namespace RayPI.SwaggerHelp
    {
        /// <summary>
        /// Swagger注释帮助类
        /// </summary>
        public class SwaggerDocTag : IDocumentFilter
        {
            /// <summary>
            /// 添加附加注释
            /// </summary>
            /// <param name="swaggerDoc"></param>
            /// <param name="context"></param>
            public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
            {
                /*
                swaggerDoc.Tags = new List<Tag>
                {
                    //添加对应的控制器描述 这个是我好不容易在issues里面翻到的
                    new Tag { Name = "Admin", Description = "后台" },
                    new Tag { Name = "Client", Description = "客户端" },
                    new Tag { Name = "System", Description = "系统" }
                };
                */
                swaggerDoc.Tags = GetControllerDesc();
            }
    
            /// <summary>
            /// 从xml注释中读取控制器注释
            /// </summary>
            /// <returns></returns>
            private List<Tag> GetControllerDesc()
            {
                List<Tag> tagList = new List<Tag>();
    
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                var xmlpath = Path.Combine(basePath, "APIHelp.xml");
                if (!File.Exists(xmlpath))//检查xml注释文件是否存在
                    return tagList;
    
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlpath);
    
                string memberName = string.Empty;//xml三级节点的name属性值
                string controllerName = string.Empty;//控制器完整名称
                string key = string.Empty;//控制器去Controller名称
                string value = string.Empty;//控制器注释
    
                foreach (XmlNode node in xmlDoc.SelectNodes("//member"))//循环三级节点member
                {
                    memberName = node.Attributes["name"].Value;
                    if (memberName.StartsWith("T:"))//T:开头的代表类
                    {
                        string[] arrPath = memberName.Split('.');
                        controllerName = arrPath[arrPath.Length - 1];
                        if (controllerName.EndsWith("Controller"))//Controller结尾的代表控制器
                        {
                            XmlNode summaryNode = node.SelectSingleNode("summary");//注释节点
                            key = controllerName.Remove(controllerName.Length - "Controller".Length, "Controller".Length);
                            if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !tagList.Contains(new Tag { Name = key }))
                            {
                                value = summaryNode.InnerText.Trim();
                                tagList.Add(new Tag { Name = key, Description = value });
                            }
                        }
                    }
                }
                return tagList;
            }
        }
    }
    View Code

    点击F5运行,控制器的注释就显示出来了。


     【20180705】再次更新显示控制器注释方法:

    这次应该是终极解决办法了,而且这个方法其实swagger已经帮我们集成好了~

    其中给swagger添加xml注释文件的函数叫“IncludeXmlComments”,F12跳转到定义,摘要是这样的:

            //
            // 摘要:
            //     Inject human-friendly descriptions for Operations, Parameters and Schemas based
            //     on XML Comment files
            //
            // 参数:
            //   filePath:
            //     An abolsute path to the file that contains XML Comments
            //
            //   includeControllerXmlComments:
            //     Flag to indicate if controller XML comments (i.e. summary) should be used to
            //     assign Tag descriptions. Don't set this flag if you're customizing the default
            //     tag for operations via TagActionsBy.
            public void IncludeXmlComments(string filePath, bool includeControllerXmlComments = false);        

    可以看到,函数其实十有两个参数的,只是第二个参数默认设置了false,而这个参数就是设置是否显示显示控制器注释的。。。

    所以只需要更改Startup.cs下ConfigureServices函数中的swagger配置就行了:

    c.IncludeXmlComments(apiXmlPath, true);//添加控制器层注释(true表示显示控制器注释)

     20180703更新:添加headers授权验证

      3. 为Swagger添加头部授权验证功能

    当接口添加了授权验证之后,我们是不能直接调用该接口,一般需要在发起的http请求的headers中添加“令牌"进行验证。用过Postman的应该知道,Postman是可以手动在headers中添加字段的,下面就要实现swagger添加headers的功能。

    这里以JWT授权验证为例,如果需要了解JWT授权验证的,可以去该系列的第四篇【从零开始搭建自己的.NET Core Api框架】(四)实战!带你半个小时实现JWT授权验证,有专门介绍。

    打开Startup.cs,我们需要在ConfigService函数中添加如下服务:

    services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "v1.1.0",
                        Title = "Ray WebAPI",
                        Description = "框架集合",
                        TermsOfService = "None",
                        Contact = new Swashbuckle.AspNetCore.Swagger.Contact { Name = "RayWang", Email = "2271272653@qq.com", Url = "http://www.cnblogs.com/RayWang" }
                    });
                    //添加注释服务
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "APIHelp.xml");
                    c.IncludeXmlComments(xmlPath);
                    //添加对控制器的标签(描述)
                    c.DocumentFilter<SwaggerDocTag>();
    
                    //手动高亮
                    //添加header验证信息
                    //c.OperationFilter<SwaggerHeader>();
                    var security = new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } }, };
                    c.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                    c.AddSecurityDefinition("Bearer", new ApiKeyScheme
                    {
                        Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                        Name = "Authorization",//jwt默认的参数名称
                        In = "header",//jwt默认存放Authorization信息的位置(请求头中)
                        Type = "apiKey"
                    });
                });

    完成之后,F5运行,swagger ui页面就会多出一个按钮"Authorize",点击可以跳出token填写页面,作用可以去看第四章,这里就不讲了


    【20180714】更新:设置swagger显示实体类信息(swagger读取多个xml注释文件) 

      4. 显示实体类注释

     我们的WebApi接口大部分都是以实体类作为对象来传输的,但是swagger如果不设置的话是看不到这些实体类的注释的。

    比如,实体类Student如下:

    “添加学生”接口,需要接收一个“Student”类:

    这里swagger只是把该实体类的字段一一列出来供测试填写数据,但是却看不到注释。

    再比如,“获取单个学生”接口,调用 后会返回一个学生实体,但是Responses信息中却只显示了一个200的状态码,而没有显示该返回的实体类的信息:

    下面,就来解决这个问题:

    1)项目生成xml注释文件

    这一步和之前一样,只是项目要选择实体类所在项目,而不是控制器层的项目:

    这里注意点是,XML文档文件的路径最好选择到控制器层XML注释文件相同的路径下,如果生成成功,打开文件夹可以看到生成的xml文件:

    2)设置swagger读取该xml注释文件

    完整的ConfigureServices下swagger配置如下:

                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "v1.1.0",
                        Title = "Ray WebAPI",
                        Description = "框架集合",
                        TermsOfService = "None",
                        Contact = new Swashbuckle.AspNetCore.Swagger.Contact { Name = "RayWang", Email = "2271272653@qq.com", Url = "http://www.cnblogs.com/RayWang" }
                    });
                    //添加注释服务
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var apiXmlPath = Path.Combine(basePath, "APIHelp.xml");
                    var entityXmlPath = Path.Combine(basePath, "EntityHelp.xml");
                    c.IncludeXmlComments(apiXmlPath, true);//控制器层注释(true表示显示控制器注释)
                    c.IncludeXmlComments(entityXmlPath);
    
                    //添加控制器注释
                    //c.DocumentFilter<SwaggerDocTag>();
    
                    //添加header验证信息
                    //c.OperationFilter<SwaggerHeader>();
                    var security = new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } }, };
                    c.AddSecurityRequirement(security);//添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称要一致,这里是Bearer。
                    c.AddSecurityDefinition("Bearer", new ApiKeyScheme
                    {
                        Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"",
                        Name = "Authorization",//jwt默认的参数名称
                        In = "header",//jwt默认存放Authorization信息的位置(请求头中)
                        Type = "apiKey"
                    });
                });

    到这,第一个问题,接受实体类就可以显示注释了:

    3)控制器的接口函数头设置标签

    在接口的头部添加标签:

    [ProducesResponseType(typeof(Student),200)]

    表明该接口返回实体类类型。如下图例:

    再次运行项目,查看获取单个学生接口:

    点击黑框上面“Model”字样,还可以查看该类的注释~

    另外,swagger还在接口的下方很贴心的生成了一个用于显示实体Model模块:

    到这,我们的第一章的内容“搭建项目和集成sawgger”就结束了,如果有问题,欢迎留言一起讨论,互相学习。

    本来想着代码比较简单,就不放源码,但是考虑之后,还是决定上传一下。正好也定个规矩,这个系列后面每完成一个大的章节之后,都上传一份源码。这样也是给自己一个交代吧。

    源码下载:点击查看下载地址

    下一章的内容是项目架构的搭建和集成SqlSugar

  • 相关阅读:
    WebView loadData乱码问题
    记录常用工具
    android toolbar学习
    百度地图V5.0地图定位
    JS调JAVA代码
    开始使用Android Stdio
    记录下平时看到的好句子
    开发者必备网址
    android:ellipsize实现跑马灯效果总结
    seo查询命令
  • 原文地址:https://www.cnblogs.com/RayWang/p/9218258.html
Copyright © 2011-2022 走看看