ASP.NET Core 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, 0);
});
}
在 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, 0);
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, 0);
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, 0);
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
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^