日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

我們在開發(fā) webapi 項目時如果遇到 api 接口需要同時支持多個版本的時候,比如接口修改了入?yún)⒅蟮怯窒MС掷习姹镜那岸耍ㄟ@里的前端可能是網(wǎng)頁,可能是App,小程序 等等)進行調(diào)用,這種情況常見于 app,畢竟網(wǎng)頁前端我們可以主動控制發(fā)布,只要統(tǒng)一發(fā)布后所有人的瀏覽器下一次訪問網(wǎng)頁時都會重新加載到最新版的代碼,但是像 app 則無法保證用戶一定會第一時間升級更新最新版的app,所以往往需要 api接口能夠同時保持多個版本的邏輯,同支持新老版本的調(diào)用端app進行調(diào)用。

針對上面的描述舉一個例子:

比如一個創(chuàng)建用戶的接口,api/user/createuser

如果我們這個時候?qū)υ摻涌诘娜雲(yún)⒑头祷貐?shù)修改之后,但是又希望原本的 api/user/createuser 接口邏輯也可以正常運行,常見的做法有以下幾種:

  1. 修改接口名稱,將新的創(chuàng)建用戶接口地址定義為 api/user/newcreateuser
  2. url傳入版本標記,將新的創(chuàng)建用戶接口地址定義為 api/user/createuser?api-version=2
  3. header傳入版本標記,通過校驗 header 中的 api-version 字段的值,用來區(qū)分調(diào)用不同版本的api

第一種方式的缺陷很明顯,當接口版本多了之后接口的地址會定義很亂,本文主要講解后面兩種方法,如何在 asp.NET webapi 項目中優(yōu)雅的使用 header 或者 query 傳入 版本標記,用來支持api的多個版本邏輯共存,并且擴展 Swagger 來實現(xiàn) SwaggerUI 對于 api-version 的支持。

截至本文撰寫時間,最新的 .net 版本為 .net6 ,本文中的所有示例也是基于 .net 6 來構(gòu)建的。

首先創(chuàng)建一個 asp.net webapi 項目,本文使用 vs2022 直接創(chuàng)建 asp.net webapi 項目

項目創(chuàng)建好之后安裝如下幾個nuget包:

Swashbuckle.AspNetCore

Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

注冊 api 版本控制服務(wù)

            #region 注冊 api 版本控制

            builder.Services.AddApiVersioning(options =>
            {
                //通過Header向客戶端通報支持的版本
                options.ReportApiVersions = true;

                //允許不加版本標記直接調(diào)用接口
                options.AssumeDefaultVersionWhenUnspecified = true;

                //接口默認版本
                //options.DefaultApiVersion = new ApiVersion(1, 0);

                //如果未加版本標記默認以當前最高版本進行處理
                options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);

                //配置為從 Header 傳入 api-version
                options.ApiVersionReader = new HeaderApiVersionReader("api-version");

                //配置為從 Query 傳入 api-version
                //options.ApiVersionReader = new QueryStringApiVersionReader("api-version");

            });

            builder.Services.AddVersionedApiExplorer(options =>
            {
                options.GroupNameFormat = "'v'VVV";
                options.SubstituteApiVersionInUrl = true;
            });

            #endregion

這里我們可以選擇 api-version 版本標記的傳入方式是從 url query 傳遞還是從 http header 傳遞。

移除項目默認的 swagger 配置

            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

采用如下 swagger 配置

            #region 注冊 Swagger

            builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerConfigureOptions>();

            builder.Services.AddSwaggerGen(options =>
            {
                options.OperationFilter<SwaggerOperationFilter>();

                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml"), true);
            });

            #endregion

其中用到了兩個自定義的類 SwaggerConfigureOptions 和 SwaggerOperationFilter ,

SwaggerConfigureOptions 是一個自定義的 Swagger 配置方法,主要用于根據(jù) api 控制器上的描述用來循環(huán)添加不同版本的 SwaggerDoc;

SwaggerOperationFilter 是一個自定義過濾器主要實現(xiàn)SwaggerUI 的版本參數(shù) api-version 必填驗證和標記過期的 api 的功能,具體內(nèi)容如下

SwaggerConfigureOptions .cs

    /// <summary>
    /// 配置swagger生成選項。
    /// </summary>
    public class SwaggerConfigureOptions : IConfigureOptions<SwaggerGenOptions>
    {
        readonly IApiVersionDescriptionProvider provider;


        public SwaggerConfigureOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;



        public void Configure(SwaggerGenOptions options)
        {
            foreach (var description in provider.ApiVersionDescriptions)
            {
                options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));

                var modelPrefix = Assembly.GetEntryAssembly()?.GetName().Name + ".Models.";
                var versionPrefix = description.GroupName + ".";
                options.SchemaGeneratorOptions = new SchemaGeneratorOptions { SchemaIdSelector = type => (type.ToString()[(type.ToString().IndexOf("Models.") + 7)..]).Replace(modelPrefix, "").Replace(versionPrefix, "").Replace("`1", "").Replace("+", ".") };
            }
        }

        static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
        {
            var info = new OpenApiInfo()
            {
                Title = Assembly.GetEntryAssembly()?.GetName().Name,
                Version = "v" + description.ApiVersion.ToString(),
                //Description = "",
                //Contact = new OpenApiContact() { Name = "", Email = "" }
            };

            if (description.IsDeprecated)
            {
                info.Description += "此 Api " + info.Version + " 版本已棄用,請盡快升級新版";
            }

            return info;
        }
    }

SwaggerOperationFilter.cs

    /// <summary>
    /// swagger 集成多版本api自定義設(shè)置
    /// </summary>
    public class SwaggerOperationFilter : IOperationFilter
    {

        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var apiDescription = context.ApiDescription;

            //判斷接口遺棄狀態(tài),對接口進行標記調(diào)整
            operation.Deprecated |= apiDescription.IsDeprecated();

            if (operation.Parameters == null)
            {
                return;
            }


            //為 api-version 參數(shù)添加必填驗證
            foreach (var parameter in operation.Parameters)
            {
                var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);

                if (parameter.Description == null)
                {
                    parameter.Description = description.ModelMetadata?.Description;
                }

                if (parameter.Schema.Default == null && description.DefaultValue != null)
                {
                    parameter.Schema.Default = new OpenApiString(description.DefaultValue.ToString());
                }

                parameter.Required |= description.IsRequired;
            }
        }
    }

這些都配置完成之后,開始對 控制模塊進行調(diào)整

為了方便代碼的版本區(qū)分,所以我這里在 Controllers 下按照版本建立的獨立的文件夾 v1 和 v2

然后在 v1 和 v2 的文件夾下防止了對于的 Controllers,如下圖的結(jié)構(gòu)

.Net WebApi 實現(xiàn) 接口版本控制并打通Swagger支持

 

然后只要在對應(yīng)文件夾下的控制器頭部加入版本標記

[ApiVersion("1")] [ApiVersion("2")] [ApiVersion("......")]

如下圖的兩個控制器

.Net WebApi 實現(xiàn) 接口版本控制并打通Swagger支持

 

這樣就配置好了兩個版本的 UserController 具體控制器內(nèi)部的代碼可以不同,然后運行 項目觀察 Swagger UI 就會發(fā)現(xiàn)如下圖:

.Net WebApi 實現(xiàn) 接口版本控制并打通Swagger支持

 

? 可以通過 SwaggerUI 右上角去切換各個版本的 SwaggerDoc

.Net WebApi 實現(xiàn) 接口版本控制并打通Swagger支持

 

?點擊單個接口的 Try it out 時接口這邊也同樣會出現(xiàn)一個 api-version 的字段,因為我們這邊是配置的從 Header 傳入該參數(shù)所以從界面中可以看出該字段是從 Header 傳遞的,如果想要從 url 傳遞,主要調(diào)整上面 注冊 api 版本控制服務(wù) 那邊的設(shè)置為從 Query 傳入即可。

至此基礎(chǔ)的 api 版本控制邏輯就算完成了。

下面衍生講解一下如果 項目中有部分 api 控制器并不需要版本控制,是全局通用的如何處理,有時候我們一個項目中總會存在一些基礎(chǔ)的 api 是基本不會變的,如果每次 api 版本升級都把所有的 控制器都全部升級顯然太過繁瑣了,所以我們可以把一些全局通用的控制器單獨標記出來。

只要在這些控制器頭部添加 [ApiVersionNeutral] 標記即可,添加了 [ApiVersionNeutral] 標記的控制器則表明該控制器退出了版本控制邏輯,無論 app 前端傳入的版本號的是多少,都可以正常進入該控制的邏輯。如下

    [ApiVersionNeutral]
    [ApiController]
    [Route("api/[controller]")]
    public class FileController : ControllerBase
    {

    }

還有一種就是當我們的 api 版本升級之后,我們希望標記某個 api 已經(jīng)是棄用的,則可以使用 Deprecated 來表示該版本的 api 已經(jīng)淘汰。

    [ApiVersion("1", Deprecated = true)]
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {

        [HttpPost("CreateUser")]
        public void CreateUser(DtoCreateUser createUser)
        {

            //內(nèi)部注冊邏輯此處省略
        }

    }

添加淘汰標記之后運行 SwaggerUI 就會出現(xiàn)下圖的樣式

.Net WebApi 實現(xiàn) 接口版本控制并打通Swagger支持

 

? 通過 SwaggerDoc 就可以很明確的看出 v1 版本的 api 已經(jīng)被淘汰了。

分享到:
標簽:Net
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定