亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

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

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

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

針對(duì)上面的描述舉一個(gè)例子:

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

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

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

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

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

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

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

Swashbuckle.AspNetCore

Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

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

            #region 注冊(cè) api 版本控制

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

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

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

                //如果未加版本標(biāo)記默認(rèn)以當(dāng)前最高版本進(jìn)行處理
                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 版本標(biāo)記的傳入方式是從 url query 傳遞還是從 http header 傳遞。

移除項(xiàng)目默認(rèn)的 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 注冊(cè) 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

其中用到了兩個(gè)自定義的類(lèi) SwaggerConfigureOptions 和 SwaggerOperationFilter ,

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

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

SwaggerConfigureOptions .cs

    /// <summary>
    /// 配置swagger生成選項(xiàng)。
    /// </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 + " 版本已棄用,請(qǐng)盡快升級(jí)新版";
            }

            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),對(duì)接口進(jìn)行標(biāo)記調(diào)整
            operation.Deprecated |= apiDescription.IsDeprecated();

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


            //為 api-version 參數(shù)添加必填驗(yàn)證
            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;
            }
        }
    }

這些都配置完成之后,開(kāi)始對(duì) 控制模塊進(jìn)行調(diào)整

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

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

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

 

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

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

如下圖的兩個(gè)控制器

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

 

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

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

 

? 可以通過(guò) SwaggerUI 右上角去切換各個(gè)版本的 SwaggerDoc

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

 

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

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

下面衍生講解一下如果 項(xiàng)目中有部分 api 控制器并不需要版本控制,是全局通用的如何處理,有時(shí)候我們一個(gè)項(xiàng)目中總會(huì)存在一些基礎(chǔ)的 api 是基本不會(huì)變的,如果每次 api 版本升級(jí)都把所有的 控制器都全部升級(jí)顯然太過(guò)繁瑣了,所以我們可以把一些全局通用的控制器單獨(dú)標(biāo)記出來(lái)。

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

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

    }

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

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

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

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

    }

添加淘汰標(biāo)記之后運(yùn)行 SwaggerUI 就會(huì)出現(xiàn)下圖的樣式

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

 

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

分享到:
標(biāo)簽:Net
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

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

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

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

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

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

答題星2018-06-03

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

全階人生考試2018-06-03

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

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

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

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

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

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定