.NET9中Swagger平替Scalar使用詳解
本文分享Swagger中常用功能在Scalar中的使用,包括版本說明、接口分類、接口及參數(shù)描述、枚舉類型、文件上傳和JWT認(rèn)證等,并提供相關(guān)代碼示例和效果展示,以及可能遇到的問題和解決方案。
書接上回,上一章介紹了Swagger代替品Scalar,在使用中遇到不少問題,今天單獨分享一下之前Swagger中常用的功能如何在Scalar中使用。
下面我們將圍繞文檔版本說明、接口分類、接口描述、參數(shù)描述、枚舉類型、文件上傳、JWT認(rèn)證等方面詳細(xì)講解。
01、版本說明
我們先來看看默認(rèn)添加后是什么樣子的。
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddOpenApi(); var app = builder.Build(); app.MapScalarApiReference(); app.MapOpenApi(); app.UseAuthorization(); app.MapControllers(); app.Run(); }
效果如下:
我們可以直接修改builder.Services.AddOpenApi()這行代碼,修改這塊描述,代碼如下:
builder.Services.AddOpenApi(options => { options.AddDocumentTransformer((document, context, cancellationToken) => { document.Info = new() { Title = "訂單微服務(wù)", Version = "v1", Description = "訂單相關(guān)接口" }; return Task.CompletedTask; }); });
我們再來看看效果。
02、接口分類
通過上圖可以看到菜單左側(cè)排列著所有接口,現(xiàn)在我們可以通過Tags特性對接口進行分類,如下圖我們把增刪改查4個方法分為冪等接口和非冪等接口兩類,如下圖:
然后我們看看效果,如下圖:
03、接口描述
之前使用Swagger我們都是通過生成的注釋XML來生成相關(guān)接口描述,現(xiàn)在則是通過編碼的方式設(shè)置元數(shù)據(jù)來生成相關(guān)描述。
可以通過EndpointSummary設(shè)置接口摘要,摘要不設(shè)置默認(rèn)為接口url,通過EndpointDescription設(shè)置接口描述,代碼如下:
//獲取 [HttpGet(Name = "")] [Tags("冪等接口")] [EndpointDescription("獲取訂單列表")] public IEnumerable<Order> Get() { return null; } //刪除 [HttpDelete(Name = "{id}")] [Tags("冪等接口")] [EndpointSummary("刪除訂單")] [EndpointDescription("根據(jù)訂單id,刪除相應(yīng)訂單")] public bool Delete(string id) { return true; }
運行效果如下:
04、參數(shù)描述
同樣可以通過Description特性來設(shè)置參數(shù)的描述,并且此特性可以直接作用于接口中參數(shù)之前,同時也支持作用于屬性上,可以看看下面示例代碼。
public class Order { [property: Description("創(chuàng)建日期")] public DateOnly Date { get; set; } [property: Required] [property: DefaultValue(120)] [property: Description("訂單價格")] public int Price { get; set; } [property: Description("訂單折扣價格")] public int PriceF => (int)(Price * 0.5556); [property: Description("商品名稱")] public string? Name { get; set; } } [HttpPut(Name = "{id}")] [Tags("非冪等接口")] public bool Put([Description("訂單Id")] string id, Order order) { return true; }
效果如下圖:
從上圖可以發(fā)現(xiàn)除了描述還有默認(rèn)值、必填項、可空等字樣,這些是通過其他元數(shù)據(jù)設(shè)置的,對于屬性還有以下元數(shù)據(jù)可以進行設(shè)置。
05、枚舉類型
對于枚舉類型,我們正常關(guān)注兩個東西,其一為枚舉項以int類型展示還是以字符串展示,其二為枚舉項顯示描述信息。
關(guān)于第一點比較簡單只要對枚舉類型使用JsonStringEnumConverter即可,代碼如下:
[JsonConverter(typeof(JsonStringEnumConverter<OrderStatus>))] public enum OrderStatus { [Description("等待處理")] Pending = 1, [Description("處理中")] Processing = 2, [Description("已發(fā)貨")] Shipped = 3, [Description("已送達")] Delivered = 4, }
效果如下:
通過上圖也可以引發(fā)關(guān)于第二點的需求,如何對每個枚舉項添加描述信息。
要達到這個目標(biāo)需要做兩件事,其一給每個枚舉項通過Description添加元數(shù)據(jù)定義,其二我們要修改文檔的數(shù)據(jù)結(jié)構(gòu)Schema。
修改builder.Services.AddOpenApi(),通過AddSchemaTransformer方法修改文檔數(shù)據(jù)結(jié)構(gòu),代碼如下:
options.AddSchemaTransformer((schema, context, cancellationToken) => { //找出枚舉類型 if (context.JsonTypeInfo.Type.BaseType == typeof(Enum)) { var list = new List<IOpenApiAny>(); //獲取枚舉項 foreach (var enumValue in schema.Enum.OfType<OpenApiString>()) { //把枚舉項轉(zhuǎn)為枚舉類型 if (Enum.TryParse(context.JsonTypeInfo.Type, enumValue.Value, out var result)) { //通過枚舉擴展方法獲取枚舉描述 var description = ((Enum)result).ToDescription(); //重新組織枚舉值展示結(jié)構(gòu) list.Add(new OpenApiString($"{enumValue.Value} - {description}")); } else { list.Add(enumValue); } } schema.Enum = list; } return Task.CompletedTask; });
我們再來看看結(jié)果。
但是這也帶來了一個問題,就是參數(shù)的默認(rèn)值也是添加描述的格式,顯然這樣的數(shù)據(jù)格式作為參數(shù)肯定是錯誤的,因此我們需要自己注意,如下圖。目前我也沒有發(fā)現(xiàn)更好的方式即可以把每項枚舉描述加上,又不影響參數(shù)默認(rèn)值,有解決方案的希望可以不吝賜教。
06、文件上傳
下面我們來看看文件上傳怎么用,直接上代碼:
[HttpPost("upload/image")] [EndpointDescription("圖片上傳接口")] [DisableRequestSizeLimit] public bool UploadImgageAsync(IFormFile file) { return true; }
然后我們測試一下效果。
首先我們可以看到請求示例中相關(guān)信息,這個相當(dāng)于告訴我們后面要怎么選擇文件上傳,我們繼續(xù)點擊Test Request。
首先請求體需要選擇multipart/form-data,上圖請求示例中已經(jīng)給出提示。
然后設(shè)置key為file,上圖請求示例中已經(jīng)給出提示,然后點擊File上傳圖片,最后點擊Send即可。
07、JWT認(rèn)證
最后我們來看看如何使用JWT認(rèn)證,
首先我們需要注入AddAuthentication及AddJwtBearer,具體代碼如下:
public class JwtSettingOption { //這個字符數(shù)量有要求,不能隨便寫,否則會報錯 public static string Secret { get; set; } = "123456789qwertyuiopasdfghjklzxcb"; public static string Issuer { get; set; } = "asdfghjkkl"; public static string Audience { get; set; } = "zxcvbnm"; public static int Expires { get; set; } = 120; public static string RefreshAudience { get; set; } = "zxcvbnm.2024.refresh"; public static int RefreshExpires { get; set; } = 10080; } builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { //取出私鑰 var secretByte = Encoding.UTF8.GetBytes(JwtSettingOption.Secret); options.TokenValidationParameters = new TokenValidationParameters() { //驗證發(fā)布者 ValidateIssuer = true, ValidIssuer = JwtSettingOption.Issuer, //驗證接收者 ValidateAudience = true, ValidAudiences = new List<string> { JwtSettingOption.Audience, JwtSettingOption.Audience }, //驗證是否過期 ValidateLifetime = true, //驗證私鑰 IssuerSigningKey = new SymmetricSecurityKey(secretByte), ClockSkew = TimeSpan.FromHours(1), //過期時間容錯值,解決服務(wù)器端時間不同步問題(秒) RequireExpirationTime = true, }; });
然后我們需要繼續(xù)修改builder.Services.AddOpenApi()這行代碼,在里面加上如下代碼:
其中BearerSecuritySchemeTransformer實現(xiàn)如下:
public sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer { public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken) { var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync(); if (authenticationSchemes.Any(authScheme => authScheme.Name == JwtBearerDefaults.AuthenticationScheme)) { var requirements = new Dictionary<string, OpenApiSecurityScheme> { [JwtBearerDefaults.AuthenticationScheme] = new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, Scheme = JwtBearerDefaults.AuthenticationScheme.ToLower(), In = ParameterLocation.Header, BearerFormat = "Json Web Token" } }; document.Components ??= new OpenApiComponents(); document.Components.SecuritySchemes = requirements; foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations)) { operation.Value.Security.Add(new OpenApiSecurityRequirement { [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = JwtBearerDefaults.AuthenticationScheme, Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>() }); } } } }
下面就可以通過[Authorize]開啟接口認(rèn)證,并實現(xiàn)一個登錄接口獲取token用來測試。
[HttpPost("login")] [EndpointDescription("登錄成功后生成token")] [AllowAnonymous] public string Login() { //登錄成功返回一個token // 1.定義需要使用到的Claims var claims = new[] { new Claim("UserId", "test") }; // 2.從 appsettings.json 中讀取SecretKey var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettingOption.Secret)); // 3.選擇加密算法 var algorithm = SecurityAlgorithms.HmacSha256; // 4.生成Credentials var signingCredentials = new SigningCredentials(secretKey, algorithm); var now = DateTime.Now; var expires = now.AddMinutes(JwtSettingOption.Expires); // 5.根據(jù)以上,生成token var jwtSecurityToken = new JwtSecurityToken( JwtSettingOption.Issuer, //Issuer JwtSettingOption.Audience, //Audience claims, //Claims, now, //notBefore expires, //expires signingCredentials //Credentials ); // 6.將token變?yōu)閟tring var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); return token; }
下面我們先用登錄接口獲取一個token。
我們先用token調(diào)用接口,可以發(fā)現(xiàn)返回401。
然后我們把上面獲取的token放進去,請求成功。
在這個過程中有可能會遇到一種情況:Auth Type后面的下拉框不可選,如下圖。
可能因以下原因?qū)е?,缺少[builder.Services.AddAuthentication().AddJwtBearer();]或[options.AddDocumentTransformer();]任意一行代碼。
注:測試方法代碼以及示例源碼都已經(jīng)上傳至代碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Planner
到此這篇關(guān)于.NET9中Swagger平替Scalar詳解(四)的文章就介紹到這了,更多相關(guān).NET9 Swagger平替Scalar內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp.net datalist綁定數(shù)據(jù)后可以上移下移實現(xiàn)示例
這篇文章主要介紹了asp.net datalist綁定數(shù)據(jù)后可以上移下移的示例代碼,需要的朋友可以參考下2014-02-02深入解析.NET 許可證編譯器 (Lc.exe) 的原理與源代碼剖析
許可證編譯器 (Lc.exe) 的作用是讀取包含授權(quán)信息的文本文件,并產(chǎn)生一個可作為資源嵌入到公用語言運行庫可執(zhí)行文件中的 .licenses 文件2013-07-07AspNetPager分頁控件UrlRewritePattern參數(shù)設(shè)置的重寫代碼
AspNetPager分頁控件UrlRewritePattern參數(shù)設(shè)置的重寫代碼,需要的朋友可以參考一下2013-02-02ASP.NET web.config中數(shù)據(jù)庫連接字符串connectionStrings節(jié)的配置方法
ASP.NET web.config中數(shù)據(jù)庫連接字符串connectionStrings節(jié)的配置方法,需要的朋友可以參考一下2013-05-05.NET Core中創(chuàng)建和使用NuGet包的示例代碼
這篇文章主要介紹了.NET Core中創(chuàng)建和使用NuGet包的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04JQuery實現(xiàn)Repeater無刷新批量刪除(附后臺asp.net源碼)
JQuery實現(xiàn)Repeater無刷新批量刪除(附后臺asp.net源碼) ,學(xué)習(xí)jquery的朋友可以參考下。2011-09-09