.net core的Swagger介面文件使用教程(二):NSwag
上一篇介紹了Swashbuckle ,地址:.net core的Swagger介面文件使用教程(一):Swashbuckle
講的東西還挺多,怎奈微軟還推薦了一個NSwag,那就繼續寫吧!
但是和Swashbuckle一樣,如果還是按照那樣寫,東西有點多了,所以這裡就偷個懶吧,和Swashbuckle對照的去寫,介紹一些常用的東西算了,所以建議看完上一篇再繼續這裡。
一、一般用法
建立一個.net core專案(這裡採用的是.net core3.1),然後使用nuget安裝NSwag.AspNetCore,建議安裝最新版本。
同樣的,假如有一個介面:
///<summary> /// 測試介面 /// </summary> [ApiController] [Route("[controller]")] public class HomeController : ControllerBase { /// <summary> /// Hello World /// </summary> /// <returns>輸出Hello World</returns> [HttpGet]public string Get() { return "Hello World"; } }
介面修改Startup,在ConfigureServices和Configure方法中新增服務和中介軟體
public void ConfigureServices(IServiceCollection services) { services.AddOpenApiDocument(settings => { settings.DocumentName= "v1"; settings.Version = "v0.0.1"; settings.Title = "測試介面專案"; settings.Description = "介面文件說明"; }); ... } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
... app.UseOpenApi(); app.UseSwaggerUi3(); ... }
然後執行專案,輸入http://localhost:5000/swagger,得到介面文件頁面:
點選Try it out可以直接呼叫介面。
同樣的,這裡的介面沒有註解,不太友好,可以和Swashbuckle一樣生成xml註釋檔案載入:
右鍵專案=》切換到生成(Build),在最下面輸出輸出中勾選【XML文件檔案】,同時,在錯誤警告的取消顯示警告中新增1591程式碼:
不過,與Swashbuckle不一樣的是,Swashbuckle需要使用IncludeXmlComments方法載入註釋檔案,如果註釋檔案不存在,IncludeXmlComments方法還會丟擲異常,但是NSwag不需要手動載入,預設xml註釋檔案和它對應點dll應該放在同一目錄且同名才能完成載入!
按照上面的操作,執行專案後,介面就有註解了:
但是控制器標籤欄還是沒有註解,這是因為NSwag的控制器標籤預設從OpenApiTagAttribute中讀取
[OpenApiTag("測試標籤",Description = "測試介面")] public class HomeController : ControllerBase
執行後顯示:
其實還可以修改這個預設行為,settings有一個UseControllerSummaryAsTagDescription屬性,將它設定成 true就可以從xml註釋檔案中載入描述了:
services.AddOpenApiDocument(settings => { ... //可以設定從註釋檔案載入,但是載入的內容可被OpenApiTagAttribute特性覆蓋 settings.UseControllerSummaryAsTagDescription = true; });
執行後顯示:
接著是認證,比如JwtBearer認證,這個和Swashbuckle是類似的,只不過拓展方法換成了AddSecurity:
public void ConfigureServices(IServiceCollection services) { services.AddOpenApiDocument(settings => { settings.DocumentName = "v1"; settings.Version = "v0.0.1"; settings.Title = "測試介面專案"; settings.Description = "介面文件說明"; //可以設定從註釋檔案載入,但是載入的內容可悲OpenApiTagAttribute特性覆蓋 settings.UseControllerSummaryAsTagDescription = true; //定義JwtBearer認證方式一 settings.AddSecurity("JwtBearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme() { Description = "這是方式一(直接在輸入框中輸入認證資訊,不需要在開頭新增Bearer)", Name = "Authorization",//jwt預設的引數名稱 In = OpenApiSecurityApiKeyLocation.Header,//jwt預設存放Authorization資訊的位置(請求頭中) Type = OpenApiSecuritySchemeType.Http, Scheme = "bearer" }); //定義JwtBearer認證方式二 settings.AddSecurity("JwtBearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme() { Description = "這是方式二(JWT授權(資料將在請求頭中進行傳輸) 直接在下框中輸入Bearer {token}(注意兩者之間是一個空格))", Name = "Authorization",//jwt預設的引數名稱 In = OpenApiSecurityApiKeyLocation.Header,//jwt預設存放Authorization資訊的位置(請求頭中) Type = OpenApiSecuritySchemeType.ApiKey }); }); ... }
到這裡,就是NSwag的一般用法了,可以滿足一般的需求了。
二、服務注入(AddOpenApiDocument和AddSwaggerDocument)
NSwag注入服務有兩個方法:AddOpenApiDocument和AddSwaggerDocument,兩者的區別就是架構型別不一樣,AddOpenApiDocument的SchemaType使用的是OpenApi3,AddSwaggerDocument的SchemaType使用的是Swagger2:
/// <summary>Adds services required for Swagger 2.0 generation (change document settings to generate OpenAPI 3.0).</summary> /// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param> /// <param name="configure">Configure the document.</param> public static IServiceCollection AddOpenApiDocument(this IServiceCollection serviceCollection, Action<AspNetCoreOpenApiDocumentGeneratorSettings, IServiceProvider> configure = null) { return AddSwaggerDocument(serviceCollection, (settings, services) => { settings.SchemaType = SchemaType.OpenApi3; configure?.Invoke(settings, services); }); } /// <summary>Adds services required for Swagger 2.0 generation (change document settings to generate OpenAPI 3.0).</summary> /// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param> /// <param name="configure">Configure the document.</param> public static IServiceCollection AddSwaggerDocument(this IServiceCollection serviceCollection, Action<AspNetCoreOpenApiDocumentGeneratorSettings, IServiceProvider> configure = null) { serviceCollection.AddSingleton(services => { var settings = new AspNetCoreOpenApiDocumentGeneratorSettings { SchemaType = SchemaType.Swagger2, }; configure?.Invoke(settings, services); ... }); ... }
個人推薦使用AddOpenApiDocument。
services.AddOpenApiDocument(settings => { //新增程式碼 });
同樣的,無論是AddOpenApiDocument還是AddSwaggerDocument,最終都是依賴AspNetCoreOpenApiDocumentGeneratorSettings來完成,與Swashbuckle不同的是,AddOpenApiDocument方法每次呼叫只會生成一個swagger介面文件物件,從上面的例子也能看出來:
DocumentName
介面文件名,也就是Swashbuckle中SwaggerDoc方法中的name引數。
Version
介面文件版本,也就是Swashbuckle中SwaggerDoc方法中的第二個OpenApiInfo的Version屬性。
Title
介面專案名稱,也就是Swashbuckle中SwaggerDoc方法中的第二個OpenApiInfo的Title屬性。
Description
介面專案介紹,也就是Swashbuckle中SwaggerDoc方法中的第二個OpenApiInfo的Description屬性。
PostProcess
這個是一個委託,在生成SwaggerDocument之後執行,需要注意的是,因為NSwag有快取機制的存在PostProcess可能只會執行一遍。
比如:因為NSwag沒有直接提供Swashbuckle中SwaggerDoc方法中的第二個OpenApiInfo的Contact屬性的配置,這時我們可以使用PostProcess實現。
settings.PostProcess = document => { document.Info.Contact = new OpenApiContact() { Name = "zhangsan", Email = "[email protected]", Url = null }; };
ApiGroupNames
無論是Swashbuckle還是NSwag都支援生成多個介面文件,但是在介面與文件歸屬上不一致:
在Swashbuckle中,通過ApiExplorerSettingsAttribute特性的GroupName屬性指定documentName來實現的,而NSwag雖然也是用ApiExplorerSettingsAttribute特性實現,但是此時的GroupName不在是documentName,而是ApiGroupNames屬性指定的元素值了:
比如下面三個介面:
/// <summary> /// 未使用ApiExplorerSettings特性,表名屬於每一個swagger文件 /// </summary> /// <returns>結果</returns> [HttpGet("All"), Authorize] public string All() { return "All"; } /// <summary> /// 使用ApiExplorerSettings特性表名該介面屬於swagger文件v1 /// </summary> /// <returns>Get結果</returns> [HttpGet] [ApiExplorerSettings(GroupName = "demo1")] public string Get() { return "Get"; } /// <summary> /// 使用ApiExplorerSettings特性表名該介面屬於swagger文件v2 /// </summary> /// <returns>Post結果</returns> [HttpPost] [ApiExplorerSettings(GroupName = "demo2")] public string Post() { return "Post"; }
定義兩個文件:
services.AddOpenApiDocument(settings => { settings.DocumentName = "v1"; settings.Version = "v0.0.1"; settings.Title = "測試介面專案"; settings.Description = "介面文件說明"; settings.ApiGroupNames = new string[] { "demo1" }; settings.PostProcess = document => { document.Info.Contact = new OpenApiContact() { Name = "zhangsan", Email = "[email protected]", Url = null }; }; }); services.AddOpenApiDocument(settings => { settings.DocumentName = "v2"; settings.Version = "v0.0.2"; settings.Title = "測試介面專案v0.0.2"; settings.Description = "介面文件說明v0.0.2"; settings.ApiGroupNames = new string[] { "demo2" }; settings.PostProcess = document => { document.Info.Contact = new OpenApiContact() { Name = "lisi", Email = "[email protected]", Url = null }; }; });
這時不用像Swashbuckle還要在中介軟體中新增文件地址,NSwag中介軟體會自動根據路由模板和文件生成文件地址資訊,所以直接執行就可以了:
可以注意到,All既不屬於v1文件也不屬於v2文件,也就是說,如果設定了ApiGroupNames,那就回嚴格的按ApiGroupNames來比較,只有匹配的GroupName在ApiGroupNames屬性中才算屬於這個介面文件,這也是NSwag和Swashbuckle不同的一點。
另外,同樣的,NSwag也支援使用IActionModelConvention和IControllerModelConvention設定GroupName,具體可以參考上一篇博文。
UseControllerSummaryAsTagDescription
這個屬性上面例子有介紹,因為NSwag的控制器標籤預設從OpenApiTagAttribute中讀取,而不是從註釋文件讀取,將此屬性設定成 true就可以從註釋文件讀取了,但是讀取的內容可被OpenApiTagAttribute特性覆蓋。
AddSecurity
AddSecurity拓展方法用於新增認證,它是兩個過載方法:
public static OpenApiDocumentGeneratorSettings AddSecurity(this OpenApiDocumentGeneratorSettings settings, string name, OpenApiSecurityScheme swaggerSecurityScheme); public static OpenApiDocumentGeneratorSettings AddSecurity(this OpenApiDocumentGeneratorSettings settings, string name, IEnumerable<string> globalScopeNames, OpenApiSecurityScheme swaggerSecurityScheme);
雖然是過載,但是兩個方法的作用差別還挺大,第一個(不帶globalScopeNames引數)的方法的作用類似Swashbuckle的AddSecurityDefinition方法,只是宣告的作用,而第二個(有globalScopeNames引數)的方法作用類似於Swashbuckle的AddSecurityRequirement方法,也就是說,這兩個過載方法,一個僅僅是宣告認證,另一個是除了宣告認證,還會將認證全域性的作用於每個介面,不過這兩個方法的實現是使用DocumentProcessors(類似Swashbuckle的DocumentFilter)來實現的
/// <summary>Appends the OAuth2 security scheme and requirement to the document's security definitions.</summary> /// <remarks>Adds a <see cref="SecurityDefinitionAppender"/> document processor with the given arguments.</remarks> /// <param name="settings">The settings.</param> /// <param name="name">The name/key of the security scheme/definition.</param> /// <param name="swaggerSecurityScheme">The Swagger security scheme.</param> public static OpenApiDocumentGeneratorSettings AddSecurity(this OpenApiDocumentGeneratorSettings settings, string name, OpenApiSecurityScheme swaggerSecurityScheme) { settings.DocumentProcessors.Add(new SecurityDefinitionAppender(name, swaggerSecurityScheme)); return settings; } /// <summary>Appends the OAuth2 security scheme and requirement to the document's security definitions.</summary> /// <remarks>Adds a <see cref="SecurityDefinitionAppender"/> document processor with the given arguments.</remarks> /// <param name="settings">The settings.</param> /// <param name="name">The name/key of the security scheme/definition.</param> /// <param name="globalScopeNames">The global scope names to add to as security requirement with the scheme name in the document's 'security' property (can be an empty list).</param> /// <param name="swaggerSecurityScheme">The Swagger security scheme.</param> public static OpenApiDocumentGeneratorSettings AddSecurity(this OpenApiDocumentGeneratorSettings settings, string name, IEnumerable<string> globalScopeNames, OpenApiSecurityScheme swaggerSecurityScheme) { settings.DocumentProcessors.Add(new SecurityDefinitionAppender(name, globalScopeNames, swaggerSecurityScheme)); return settings; }
而SecurityDefinitionAppender是一個實現了IDocumentProcessor介面的類,它實現的Porcess如下,其中_scopeNames就是上面方法傳進來的globalScopeNames:
/// <summary>Processes the specified Swagger document.</summary> /// <param name="context"></param> public void Process(DocumentProcessorContext context) { context.Document.SecurityDefinitions[_name] = _swaggerSecurityScheme; if (_scopeNames != null) { if (context.Document.Security == null) { context.Document.Security = new Collection<OpenApiSecurityRequirement>(); } context.Document.Security.Add(new OpenApiSecurityRequirement { { _name, _scopeNames } }); } }
至於其他用法,可以參考上面的一般用法和上一篇中介紹的Swashbuckle的AddSecurityDefinition方法和AddSecurityRequirement方法的用法,很相似。
DocumentProcessors
DocumentProcessors類似於Swashbuckle的DocumentFilter方法,只不過DocumentFilter方法時實現IDocumentFilter介面,而DocumentProcessors一個IDocumentProcessor集合屬性,是需要實現IDocumentProcessor介面然後新增到集合中去。需要注意的是,因為NSwag有快取機制的存在DocumentProcessors可能只會執行一遍。
另外,你可能注意到,上面有介紹過一個PostProcess方法,其實個人覺得PostProcess和DocumentProcessors區別不大,但是DocumentProcessors是在PostProcess之前呼叫執行,原始碼中:
public async Task<OpenApiDocument> GenerateAsync(ApiDescriptionGroupCollection apiDescriptionGroups) { ...
foreach (var processor in Settings.DocumentProcessors) { processor.Process(new DocumentProcessorContext(document, controllerTypes, usedControllerTypes, schemaResolver, Settings.SchemaGenerator, Settings)); } Settings.PostProcess?.Invoke(document); return document; }
可能是作者覺得DocumentProcessors有點繞,所以提供了一個委託供我們簡單處理吧,用法也可以參考上一篇中的Swashbuckle的DocumentFilter方法,比如全域性的新增認證,全域性的新增Server等等。
OperationProcessors
OperationProcessors類似Swashbuckle的OperationFilter方法,只不過OperationFilter實現的是IOperationFilter,而OperationProcessors是IOperationProcessor介面集合。需要注意的是,因為NSwag有快取機制的存在OperationProcessors可能只會執行一遍。
同樣的,可能作者為了方便我們使用,已經定義好了一個OperationProcessor類,我們可以將我們的邏輯當做引數去例項化OperationProcessor類,然後新增到OperationProcessors集合中即可,不過作者還提供了一個AddOperationFilter方法,可以往OperationProcessors即可開始位置新增過期操作:
/// <summary>Inserts a function based operation processor at the beginning of the pipeline to be used to filter operations.</summary> /// <param name="filter">The processor filter.</param> public void AddOperationFilter(Func<OperationProcessorContext, bool> filter) { OperationProcessors.Insert(0, new OperationProcessor(filter)); }
所以我們可以這麼用:
settings.AddOperationFilter(context => { //我們的邏輯 return true; });
另外,因為無論使用AddOperationFilter方法,還是直接往OperationProcessors集合中新增IOperationProcessor物件,都會對所有Action(或者說Operation)進行呼叫,NSwag還有一個SwaggerOperationProcessorAttribute特性,用於指定某些特定Action才會呼叫執行。當然,SwaggerOperationProcessorAttribute的例項化需要指定一個實現了IOperationProcessor介面的型別以及例項化它所需要的的引數。
與Swashbuckle不同的是,IOperationProcessor的Process介面要求返回一個bool型別的值,表示介面是否要在swaggerUI頁面展示,如果返回false,介面就不會在前端展示了,而且後續的IOperationProcessor物件也不再繼續呼叫執行。
private bool RunOperationProcessors(OpenApiDocument document, Type controllerType, MethodInfo methodInfo, OpenApiOperationDescription operationDescription, List<OpenApiOperationDescription> allOperations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) { var context = new OperationProcessorContext(document, operationDescription, controllerType, methodInfo, swaggerGenerator, Settings.SchemaGenerator, schemaResolver, Settings, allOperations); // 1. Run from settings foreach (var operationProcessor in Settings.OperationProcessors) { if (operationProcessor.Process(context)== false) { return false; } } // 2. Run from class attributes var operationProcessorAttribute = methodInfo.DeclaringType.GetTypeInfo() .GetCustomAttributes() // 3. Run from method attributes .Concat(methodInfo.GetCustomAttributes()) .Where(a => a.GetType().IsAssignableToTypeName("SwaggerOperationProcessorAttribute", TypeNameStyle.Name)); foreach (dynamic attribute in operationProcessorAttribute) { var operationProcessor = ObjectExtensions.HasProperty(attribute, "Parameters") ? (IOperationProcessor)Activator.CreateInstance(attribute.Type, attribute.Parameters) : (IOperationProcessor)Activator.CreateInstance(attribute.Type); if (operationProcessor.Process(context) == false) { return false; } } return true; }
至於其它具體用法,具體用法可以參考上一篇介紹的Swashbuckle的OperationFilter方法,如給特定Operation新增認證,或者對響應介面包裝等等。
其它配置
AspNetCoreOpenApiDocumentGeneratorSettings繼承於OpenApiDocumentGeneratorSettings和JsonSchemaGeneratorSettings還有茫茫多的配置,感興趣的自己看原始碼吧,畢竟它和Swashbuckle差不多,一般的需求都能滿足了,實現滿足不了,可以使用DocumentProcessors和OperationProcessors來實現,就跟Swashbuckle的DocumentFilter和OperationFilter一樣。
但是有些問題可能就不行了,比如虛擬路徑問題,Swashbuckle採用在Server上加路徑來實現,而因為NSwag沒有像Swashbuckle的AddServer方法,想到可以使用上面的PostProcess方法或者使用DocumentProcessors來實現,但是現實是打臉,因為作者的處理方式是,執行PostProcess方法和DocumentProcessors之後,會把OpenAPIDocument上的Servers先清空,然後再加上當前SwaggerUI所在的域名地址,可能作者覺著這樣能滿足大部分人的需求吧。但是作者還是提供了其他的方式來操作,會在後面的中介軟體中介紹
三、新增Swagger中介軟體(UseOpenApi、UseSwagger和UseSwaggerUi3、UseSwaggerUi)
UseOpenApi、UseSwagger
首先UseOpenApi、UseSwagger和Swashbuckle的UseSwagger的作用一樣的,主要用於攔截swagger.json請求,從而可以獲取返回所需的介面架構資訊,不同點在於NSwag的UseOpenApi、UseSwagger具有快取機制,也就是說,如果第一次獲取到了介面文件,會已json格式將文件加入到本地快取中,下次直接從快取獲取,因為快取的存在,所以上面介紹的OperationProcessors和DocumentProcessors都不會再執行了。
另外,UseSwagger是舊版本,已經不推薦使用了,推薦使用UseOpenApi:
app.UseOpenApi(settings => { //中介軟體設定 });
OpenApiDocumentMiddlewareSettings
UseOpenApi依賴OpenApiDocumentMiddlewareSettings物件完成配置過程,主要屬性有:
Path
Path表示攔截請求的格式,也就是攔截swagger.json的路由格式,這個跟Swashbuckle一樣,因為需要從路由知道是哪個文件,然後才能去找這個文件的所有介面解析返回,它的預設值是/swagger/{documentName}/swagger.json。
同樣的,因為這個值關係比較重要,儘可能不要去修改吧。
DocumentName
從上面的Path引數的預設值中可以看到,其中有個{documentName}引數,NSwag並沒有要求Path中必須有{documentName}引數。
如果沒有這個引數,就必須指定這個屬性DocumentName,只是也就是說NSwag只為一個介面文件服務。
如果有這個引數,NSwag會遍歷所有定義的介面文件,然後分別對Path屬性替換掉其中中的{documentName}引數,然後分別攔截每個文件獲取架構資訊的swagger.json請求。
PostProcess
服務注入部分有一個PostProcess方法,功能其實類似於DocumentProcessors,就是對介面文件做一個調整,而現在這裡又有一個PostProcess方法,它則是根據當前請求來調整介面文件用的。
比如,上面有介紹,如果在服務注入部分使用PostProcess方法或者DocumentProcessors添加了Server,是沒有效果的,這個是因為NSwag在獲取到文件之後,有意的清理了文件的Servers屬性,然後加上了當前請求的地址:
/// <summary>Generates the Swagger specification.</summary> /// <param name="context">The context.</param> /// <returns>The Swagger specification.</returns> protected virtual async Task<OpenApiDocument> GenerateDocumentAsync(HttpContext context) { var document = await _documentProvider.GenerateAsync(_documentName); document.Servers.Clear(); document.Servers.Add(new OpenApiServer { Url = context.Request.GetServerUrl() }); _settings.PostProcess?.Invoke(document, context.Request); return document; }
注意到上面的原始碼,在清理之後,還呼叫了這個PostProcess委託,因此,我們可以將新增Server部分的程式碼寫到這個PostProcess中:
app.UseOpenApi(settings => { settings.PostProcess = (document, request) => { //清理掉NSwag加上去的 document.Servers.Clear(); document.Servers.Add(new OpenApiServer() { Url = "http://localhost:90/NSwag", Description = "地址1" }); document.Servers.Add(new OpenApiServer() { Url = "http://127.0.0.1:90/NSwag", Description = "地址2" }); //192.168.28.213是我本地IP document.Servers.Add(new OpenApiServer() { Url = "http://192.168.28.213:90/NSwag", Description = "地址3" }); }; });
看來,作者還是很友好的,做了點小動作還提供給我們一個修改的方法。
CreateDocumentCacheKey
上面有提到,NSwag的介面文旦有快取機制,第一次獲取之後就會以json格式被快取,接下就會從快取中讀取,而CreateDocumentCacheKey就是快取的鍵值工廠,用於生成快取鍵值用的,如果不設定,那麼快取的鍵值就是string.Empty。
那可能會問,如果不想用快取呢,不妨設定CreateDocumentCacheKey成這樣:
app.UseOpenApi(settings => { settings.CreateDocumentCacheKey = request => DateTime.Now.ToString(); });
然後你就會發現,過了一段時間之後,你的程式掛了,OutOfMemory!
所以,好好的用快取的,從原始碼中目前沒發現有什麼辦法可以取消快取,況且使用快取可以提高響應速度,為何不用?如果實在要遮蔽快取,那就是改改原始碼再編譯引用吧。
ExceptionCacheTime
既然是程式,那就有可能會丟擲異常,獲取介面文件架構也不例外,而ExceptionCacheTime表示在獲取介面文件發生異常後的一段時間內,使用返回這個異常,ExceptionCacheTime預設是TimeSpan.FromSeconds(10)
UseSwaggerUi3、UseSwaggerUi
UseSwaggerUi3、UseSwaggerUi的作用和Swashbuckle的UseSwaggerUI作用是一樣,主要用於攔截swagger/index.html頁面請求,返回頁面給前端。
UseSwaggerUi返回的是基於Swagger2.0的頁面,而UseSwaggerUi3返回的是基於Swagger3.0的頁面,所以這裡推薦使用UseSwaggerUi3
app.UseSwaggerUi3(settings => { //中介軟體操作 });
SwaggerUi3Settings
UseSwaggerUi3依賴SwaggerUi3Settings完成配置,SwaggerUi3Settings繼承於SwaggerUiSettingsBase和SwaggerSettings,所以屬性比較多,這裡介紹常用的一些屬性:
EnableTryItOut
這個屬性很簡單,就是設定允許你是否可以在SwaggerUI使用Try it out去呼叫介面
DocumentTitle
這是SwaggerUI頁面的Title資訊,也就是返回的html的head標籤下的title標籤值,預設是 Swagger UI
CustomHeadContent
自定義頁面head標籤內容,可以使用自定義的指令碼和樣式等等,作用於Swashbuckle中提到的HeadContent是一樣的
Path
Path是SwaggerUI的index.html頁面的地址,作用與Swashbuckle中提到的RoutePrefix是一樣的
CustomInlineStyles
自定外部樣式,不是連結,就是具體的樣式!
CustomInlineStyles
自定義的外部樣式檔案的連結
CustomJavaScriptPath
自定義外部JavaScript指令碼檔案的連線
DocumentPath
介面文件獲取架構swagger.json的Url模板,NSwag不需要想Swashbuckle呼叫SwaggerEndpoint新增文件就是因為它會自動根據這個將所有文件按照DocumentPath的格式進行設定,它的預設值是/swagger/{documentName}/swagger.json。
同樣的,儘可能不要修改這個屬性,如果修改了,切記要和上面介紹的OpenApiDocumentMiddlewareSettings的Path屬性同步修改。
SwaggerRoutes
這是屬性包含了介面文件列表,在Swashbuckle中是通過SwaggerEndpoint方法新增的,但是NSwag會自動生成根據DocumentPath屬性自動生成。
app.UseSwaggerUi3(settings => { settings.SwaggerRoutes.Add(new NSwag.AspNetCore.SwaggerUi3Route("demo", "/swagger/v1/swagger.json")); });
需要注意的是,如果自己往SwaggerRoutes中新增介面文件物件,那麼NSwag不會自動生成了,比如上面的例子,雖然定義了多個文件,但是我們手動往SwaggerRoutes添加了一個,那SwaggerUI中就只會顯示我們自己手動新增的了。
TransformToExternalPath
TransformToExternalPath其實是一個路徑轉化,主要是轉換swagger內部的連線,比如獲取架構新的的請求 /swagger/v1/swagger.json和獲取swaggerUI頁面的連線 /swagger,這個很有用,比如上面提到的虛擬路徑處理的一個完整的例子:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NSwag; namespace NSwagDemo { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddOpenApiDocument(settings => { settings.DocumentName = "v1"; settings.Version = "v0.0.1"; settings.Title = "測試介面專案"; settings.Description = "介面文件說明"; settings.ApiGroupNames = new string[] { "demo1" }; settings.PostProcess = document => { document.Info.Contact = new OpenApiContact() { Name = "zhangsan", Email = "[email protected]", Url = null }; }; settings.AddOperationFilter(context => { //我們的邏輯 return true; }); //可以設定從註釋檔案載入,但是載入的內容可被OpenApiTagAttribute特性覆蓋 settings.UseControllerSummaryAsTagDescription = true; //定義JwtBearer認證方式一 settings.AddSecurity("JwtBearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme() { Description = "這是方式一(直接在輸入框中輸入認證資訊,不需要在開頭新增Bearer)", Name = "Authorization",//jwt預設的引數名稱 In = OpenApiSecurityApiKeyLocation.Header,//jwt預設存放Authorization資訊的位置(請求頭中) Type = OpenApiSecuritySchemeType.Http, Scheme = "bearer" }); //定義JwtBearer認證方式二 settings.AddSecurity("JwtBearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme() { Description = "這是方式二(JWT授權(資料將在請求頭中進行傳輸) 直接在下框中輸入Bearer {token}(注意兩者之間是一個空格))", Name = "Authorization",//jwt預設的引數名稱 In = OpenApiSecurityApiKeyLocation.Header,//jwt預設存放Authorization資訊的位置(請求頭中) Type = OpenApiSecuritySchemeType.ApiKey }); }); services.AddAuthentication(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); //NSwag是虛擬路徑 var documentPath = "/swagger/{documentName}/swagger.json"; app.UseOpenApi(settings => { settings.PostProcess = (document, request) => { //清理掉NSwag加上去的 document.Servers.Clear(); document.Servers.Add(new OpenApiServer() { Url = "http://localhost:90/NSwag", Description = "地址1" }); document.Servers.Add(new OpenApiServer() { Url = "http://127.0.0.1:90/NSwag", Description = "地址2" }); //192.168.28.213是我本地IP document.Servers.Add(new OpenApiServer() { Url = "http://192.168.28.213:90/NSwag", Description = "地址3" }); }; settings.Path = documentPath; }); app.UseSwaggerUi3(settings => { //settings.SwaggerRoutes.Add(new NSwag.AspNetCore.SwaggerUi3Route("demo", "/swagger/v1/swagger.json")); settings.TransformToExternalPath = (s, r) => { if (s.EndsWith("swagger.json")) { return $"/NSwag{s}"; } return s; }; }); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }虛擬路徑例子
比如這裡我們的虛擬路徑是NSwag,使用IIS部署:
專案執行後
四、總結
後面還有東西就不寫了,還是那三個注意點:
主要就是記住三點:
1、服務注入使用AddOpenApiDocument方法(儘量不要用AddSwaggerDocument),主要就是生成介面相關資訊,如認證,介面註釋等等,還有幾種過濾器幫助我們實現自己的需求
2、中介軟體注入有兩個:UseOpenApi(儘量不要使用UseSwagger,後續版本將會被移除)和UseSwaggerUi3(儘量不要使用UseSwaggerUi,後續版本將會被移除):
UseOpenApi負責返回介面架構資訊,返回的是json格式的資料
UseSwaggerUi3負責返回的是頁面資訊,返回的是html內容
3、如果涉及到介面生成的,儘可能在AddOpenApiDocument中實現,如果涉及到UI頁面的,儘可能在UseSwaggerUi3中實現