選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
6 分鐘閱讀時間 (1130 個字)

ASP.NET Core Web API 版本的做法

markus-spiske-207946
Web API 版本(Versioning)的做法有很多種,

在 URL 上面、QueryString 的參數,或是在 Header 中。

本文就來看看 ASP.NET Core Web API 多版本的做法。
本文參考自「Support multiple versions of ASP.NET Core Web API

當新增好 ASP.NET Core Web API 專案後,預設有一個 Values 的 API 可以測試,

以下我們就一步步的來看看 API 版本的各種做法。

1.加入 Microsoft.AspNetCore.Mvc.Versioning 套件


 

2.在 Statrup.cs 檔案的 ConfigureServices Method中設定 Versioning

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(opt =>
{
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new ApiVersion(1, );
});
}
在 AddApiVersioning 中有3個設定值,

ReportApiVersions: 如果這個設 true 的話,就會將支援的版本列在 header 之中。
DefaultApiVersion: 設定 API 預設的版本。
AssumeDefaultVersionWhenUnspecified: 設個設 true 的話,使用時如果沒特別指定的話,就會用 DefaultApiVersion 設定的版本。

所以我們 GET /api/values 回傳的 Header 中就會有 api-supported-versions 這個內容,如下,

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Kestrel
api-supported-versions: 1.0

註: ReportApiVersions 預設值為 fase 。

3.建立不同版本的 API

3.1.舊有的 api 設定版本為 1.0,在 ValuesController Class上設定 ApiVersion 屬性,如下
namespace WebAPIVersionDemo.Controllers{
[ApiVersion("1.0")]
[Route("api/[controller]")]
public class ValuesController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "api v1" };
}
}
}
3.2.新增一個 version 2.0 的 Controller (不同 namespace 相同 Controller name)
namespace WebAPIVersionDemo.ControllersV2{
[ApiVersion("2.0")]
[Route("api/[controller]")]
public class ValuesController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] {"api v2"};
}
}
}
3.3.預設是 Version 1.0 ,內容如下,


4.透過 QueryString 指定呼叫的 Version

4.1.呼叫 2.0 (?api-version=2)



4.2.呼叫 1.0 (?api-version=1)



註:如果給不同的版本會發生錯誤哦! 如下,

5.在 URL Route 中指定,例如 api/v1/values or api/v2/values

5.1.設定 Controller 的 Route 屬性,來 Support
namespace WebAPIVersionDemo.Controllers{
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ValuesController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "api v1" };
}
}
}

6.透過 HTTP Headers 指定呼叫的 Version

6.1.先將原本在 Controller 上的 Route 屬性從 Route("api/v{version:apiVersion}/[controller]") 改回原本的 Route("api/[controller]")

6.2.在 Statrup.cs 檔案的 ConfigureServices Method中設定 從 Header 讀取 Versioning 的資訊,如下,
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(opt =>
{
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new ApiVersion(1, );
opt.ApiVersionReader = new HeaderApiVersionReader("api-version");
});
}
6.3.所以在header 中加入 api-version:1 or api-version:2 就可以呼叫想要的版本,如下,


7.透過 HTTP Headers 或 QueryString 都可指定呼叫的 Version

如果想要讓 HTTP Headers 或 QueryString 都可指定呼叫的 Version 的話,可以在 Statrup.cs 檔案的 ConfigureServices Method中設定。將 HeaderApiVersionReader 改成 QueryStringOrHeaderApiVersionReader ,如下,
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(opt =>
{
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new ApiVersion(1, );
opt.ApiVersionReader = new QueryStringOrHeaderApiVersionReader()
{ HeaderNames = { "api-version", "x-ms-version" } };
});
}
這樣子的話,如果 Header 給 api-version:1 或是 x-ms-version:2 都可以。

因為 QueryStringOrHeaderApiVersionReader 沒有傳入參數名稱,所以 QueryString 預設值為 api-version,所以使用上跟 上述第4點一樣。

如果要改 QueryString 的參數名稱可以在建立 QueryStringOrHeaderApiVersionReader 時指定,例如設定為 v ,如下
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(opt =>
{
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new ApiVersion(1, );
opt.ApiVersionReader = new QueryStringOrHeaderApiVersionReader("v")
{ HeaderNames = { "api-version", "x-ms-version" } };
});
}

8.MapToApiVersion

有時候 API 升級並不是整個都重寫,如果在原本的 Controller 之中擴充的話,

就可以在 Controller 多加入 ApiVersion 的宣告,如下加入 V3.0 ,
namespace WebAPIVersionDemo.Controllers{
[ApiVersion("1.0")]
[ApiVersion("3.0")]
[Route("api/[controller]")]
public class ValuesController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "api v1" };
}
}
}


這時如果在原本的Controller中 v3.0 要用另一個 Method 實作的話,就可以使用 MapToApiVersion 去設定,如下,
namespace WebAPIVersionDemo.Controllers{
[ApiVersion("1.0")]
[ApiVersion("3.0")]
[Route("api/[controller]")]
public class ValuesController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "api v1" };
}

[HttpGet, MapToApiVersion("3")]
public IEnumerable<string> GetV3()
{
return new string[] { "api v3" };
}
}
}

9.Deprecated

如果有些 api 將來要刪掉的話,可加入 deprecated 來讓使用的人知道,如下,

[ApiVersion("1.0", Deprecated=true)]

所以在 Headers 中就會有 api-deprecated-versions 值為 1.0, api-supported-versions 值就變成了 2.0, 3.0 ,如下,


10.ApiVersionNeutral

如果我們再新增一個 RMController (GetRequestedApiVersion Method,可以取得 Client Request 的版本號),如下,
namespace WebAPIVersionDemo.ControllersNeutral{
[Route("api/[controller]")]
public class RMController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { $"api v {HttpContext.GetRequestedApiVersion()}" };
}
}
}
因為沒有指定版本號,而 ValuesController 中的版本號有 1 ~ 3,所以我們可以呼叫 RMController 並指定版本號為 1 ~ 3。

如果指定版本4的話,就會發生錯誤。

如果想要讓這個 Controller 不管什麼版本都可以 Work 的話,就可以多設定 ApiVersionNeutral 這個屬性,如下,
namespace WebAPIVersionDemo.ControllersNeutral{
[ApiVersionNeutral]
[Route("api/[controller]")]
public class RMController : Controller {
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { $"api v {HttpContext.GetRequestedApiVersion()}" };
}
}
}

參考資料

Support multiple versions of ASP.NET Core Web API
ASP.NET Core RESTful Web API versioning made easy
 
本文也發表於 亂馬客Blog
ASP.NET Core Middleware
為什麼我的 APS.Net Form Authentication 在 timeout 時間還沒到前...
 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/04, 週六

Captcha 圖像