【從零開始搭建自己的.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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM