在本教程中,我们将学习如何开发简单的 Asp Net Core 3.1 Web API 和 API 版本控制技术,例如基于 URL、基于header和基于查询字符串的版本控制。
什么是 Web API 版本控制?为什么我们需要它?
假设我们在生产箱中有一个可用的 API,并且一些客户已经在使用它。后期生产部署,我们应该非常小心任何新的变化。这些更改不应影响已经使用我们 API 的现有客户应用程序。建议客户在集成了我们 API 的每个应用程序中更改 API 调用并不是一个好的做法。为了解决这些问题,API 版本控制出现了。
API 版本确保我们现有客户端应用程序数据的完整性和可用性。
对于实施,我将使用,
- 微软 Visual Studio 企业版 2019
- Version 16.8.4
- ASP.NET Core 3.1
- 用于Postman 测试 API
可以使用Visual Studio 2019 社区版。
首先,
第1步
创建一个简单的 ASP.NET Core 3.1 API 项目。
第2步
添加模型 ProductResponse.cs
namespace AspNetCoreVersioning.Contracts {
public class ProductResponse {
public Guid Id {
get;
set;
}
public string Name {
get;
set;
}
}
}
第 3 步
添加控制器 ProductsController.cs
namespace AspNetCoreVersioning.Controllers {
[ApiController]
[Route("api/products")]
public class ProductsController: ControllerBase {
[HttpGet("{productId}")]
public IActionResult GetProduct([FromRoute] Guid productId) {
var product = new ProductResponse {
Id = productId,
Name = "Sanitizer"
};
return Ok(product);
}
}
}
让我们来测试这个 API,根据您的环境,端口号会有所不同。
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000
结果
{"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}
我们已经收到了预期的结果。
假设我们需要对 API 进行重大更改,但我们不想破坏客户已经在使用的现有 API 中的任何内容。我们怎样才能做到这一点?让我们去解析一个 NuGet 包Microsoft.AspNetCore.Mvc.Versioning。
从包管理器控制台使用以下命令,
Install-Package Microsoft.AspNetCore.Mvc.Versioning
软件包安装完成后,让我们配置 API 以支持版本控制。这个包基本上有我们需要的一切。
事不宜迟,让我们转到类 Startup.cs,我们将在其中更新 ConfigurationServices 方法,如下所示
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddApiVersioning();
}
通过添加这些 services.AddApiVersioning() 方法,我们有某种版本控制。但是,我们还没有真正告诉 ASP.NETCore 我们如何对 API 进行版本控制。不做任何额外更改,让我们运行 API,我们将收到以下错误消息
{"error":{"code":"ApiVersionUnspecified","message":"An API version is required, but was not specified.","innerError":null}}
这是因为我们尚未将 API 版本控制配置为默认版本。对于我们来说,第一个版本显然是 V1 或 V1.0。这在 ASP.NET Core 中的默认工作方式是使用“API-version”查询字符串参数,如下所示。
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=1
结果如下,
{"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}
然而,这并不理想,因为如果我们强制要求这个“api-version”查询字符串,我们的许多消费者的代码就会中断。我们想要做的是我们希望启用 API 版本控制默认为一个版本。我们如何才能做到这一点?让我们再次进入 Startup.cs 类并进行以下更改。
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddApiVersioning(options => {
options.AssumeDefaultVersionWhenUnspecified = true;
});
}
让我们再次执行 API,
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000
Result: {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}
假设,如果我们想要一个不同的版本而不是 V1.0 或 V1。我们怎样才能做到这一点?
首先,我们将在 Startup.cs 类中进行以下更改,如下所示,
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddApiVersioning(options => {
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = ApiVersion.Default;
});
}
然后进行以下两个更改。
第1步
在 ProductResponse.cs 类中添加以下模型,
namespace AspNetCoreVersioning.Contracts {
public class ProductResponseV1 {
public Guid Id {
get;
set;
}
public string Name {
get;
set;
}
}
public class ProductResponseV2 {
public Guid Id {
get;
set;
}
public string ProductName {
get;
set;
}
}
}
第2步
对 ProductsController.cs 类进行以下更改
namespace AspNetCoreVersioning.Controllers {
[ApiController]
[Route("api/products")]
public class ProductsController: ControllerBase {
[HttpGet("{productId}")]
public IActionResult GetProductV1([FromRoute] Guid productId) {
var product = new ProductResponseV1 {
Id = productId,
Name = "Sanitizer"
};
return Ok(product);
}
[HttpGet("{productId}")]
public IActionResult GetProductV2([FromRoute] Guid productId) {
var product = new ProductResponseV2 {
Id = productId,
ProductName = "Sanitizer"
};
return Ok(product);
}
}
现在运行 API。您将收到以下异常。
处理请求时发生未处理的异常。
AmbiguousMatchException: The request matched multiple endpoints. Matches,
AspNetCoreVersioning.Controllers.ProductsController.GetProductV2 (AspNetCoreVersioning)
AspNetCoreVersioning.Controllers.ProductsController.GetProductV1 (AspNetCoreVersioning)
Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
为了解决此错误消息,我们需要在 ProductsController.cs 类中进行一些配置更改,如下所示,
namespace AspNetCoreVersioning.Controllers {
[ApiController]
[Route("api/products")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ProductsController: ControllerBase {
[HttpGet("{productId}")]
public IActionResult GetProductV1([FromRoute] Guid productId) {
var product = new ProductResponseV1 {
Id = productId,
Name = "Sanitizer"
};
return Ok(product);
}
[HttpGet("{productId}")]
[MapToApiVersion("2.0")]
public IActionResult GetProductV2([FromRoute] Guid productId) {
var product = new ProductResponseV2 {
Id = productId,
ProductName = "Sanitizer"
};
return Ok(product);
}
}
}
现在运行 API,如下所示,
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=1
Result: {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=2
Result: {"id":"00000000-0000-0000-0000-000000000000","productName":"Sanitizer"}
我将在接下来的会议中介绍基于 URL 和基于Head的版本控制。感谢您阅读我的文章。我感谢您在下面的评论部分中的反馈。