ASP.NET Core Web API 版本控制
在nuget.org上,您可以找到 Microsoft.AspNetCore.Mvc.Versioning包,它提供了有关如何对Web API端点进行版本化的更多选项。这个包的好处是允许你直接在控制器上使用带参数的属性,因此使用起来非常方便。
另一个好处是您可以选择向客户端报告它不支持尝试调用的版本。在Startup.cs类中添加versionign服务时,只需启用此选项即可
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o => o.ReportApiVersions = true);
}
如果您刚开始对API进行版本控制并且到目前为止还没有版本标识,那么您也可以设置默认版本控制。所有没有版本控制数据的请求
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1,0);
});
}
注意
确保您的默认版本未在控制器上标记为已弃用,并且您的客户端调用不会被控制器上版本控制属性声明的版本控制策略拒绝
让我们从不同版本控制选项的一些代码示例和设置开始,看看在实践中所有这些都是如此。
基于参数的版本控制
开箱即用支持查询字符串版本控制,因此通过发送api-version = 1.0,我们告诉应用程序以版本属性1.0路由到控制器
namespace Core.Versioning.Sample.Controllers
{
[ApiVersion("1.0")]
[Route("api/[controller]")]
public class ValueController : Controller
{
[HttpGet]
public String Get()
{
return "Version 1.0";
}
}
}
要添加新版本,我们可以在具有ApiVersion属性的不同命名空间内将相同的控制器名称添加到新版本
namespace Core.Versioning.Sample.Controllers.v2
{
[ApiVersion("2.0")]
[ApiVersion("1.0", Deprecated = true)]
[Route("api/[controller]")]
public class ValueController : Controller
{
[HttpGet]
public String Get()
{
return "Version 2.0";
}
}
}
现在让我们’测试不同api-version参数值的响应
$ curl http:// localhost:5000 / api / value?api-version = 1.0 -iHTTP / 1.1 200 OK
日期:星期四,2018年6月14日08:11:13 GMT
内容类型:text / plain; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:1.0,2.0Version 1.0
对于2.0版本,响应会有所不同
$ curl http:// localhost:5000 / api / value?api-version = 2.0 -iHTTP / 1.1 200 OK
日期:星期四,2018年6月14日08:11:19 GMT
内容类型:text / plain; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:1.0,2.0
现在我将尝试使用不受支持的3.0版调用API。让我们看看在这种情况下会发生什么
$ curl http:// localhost:5000 / api / value?api-version = 3.0 -iHTTP / 1.1 400 Bad Request
Date:Thu,14 Jun 2018 08:16:12 GMT
Content-Type:application / json; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:1.0,2.0{
“error”:{
“code”:“UnsupportedApiVersion”,
“message”:“与请求URI匹配的HTTP资源” http:// localhost:5000 / api / value?api-version = 3.0’不支持API版本’3.0’。“,
”innerError“:null
}
}
您看到响应代码不是200 OK,但400 Bad Request with JSON消息表明此版本不受支持。
基于标题的版本控制
如果将版本作为查询字符串值发送到Web API端点不够好,则可以使用标头。对于这种版本控制方式,您需要在Startup.cs 文件中进行一些小的更改, 以告知版本控制包在特定键的标头中查找版本值。我选择使用与我用于api-version的查询字符串相同的方法
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1,0);
o.ApiVersionReader = new HeaderApiVersionReader(“api-version”);
});
}
您可以 通过在请求标头中添加api-version值,使用POSTMAN轻松测试 。使用此方法,您将始终使用具有不同请求标头值的相同端点URL来访问不同版本的端点。
为了进行快速测试以确认这是有效的,让我们在标题中调用2.0版本的API
$ curl –header“api-version:2.0”http:// localhost:5000 / api / value -iHTTP / 1.1 200 OK
日期:星期四,2018年6月14日08:27:49 GMT
内容类型:text / plain ; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:1.0,2.0Version 2.0
基于路由的版本控制
基于路由的版本控制基于控制器的url结构,并期望路由包含版本。为此,我们需要将Startup.cs更改为不再从标题中读取,而是查看URL
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1,0);
o.ApiVersionReader = new UrlSegmentApiVersionReader();
});
}
为了支持我们设置为1.0的默认版本,我们还需要为没有版本段的特定版本提供额外的路由,否则默认版本将不起作用
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ApiVersionReader = new HeaderApiVersionReader("api-version");
});
}
这里感谢LamondLu的博客,其HeaderApiVersionReader已经淘汰,应该如以下代码:
services.AddApiVersioning(
o => o.ApiVersionReader = ApiVersionReader.Combine(
new QueryStringApiVersionReader(),
new HeaderApiVersionReader()
{
Headers = { "api-version" }
} ) );
您可以 通过在请求标头中添加api-version值,使用POSTMAN轻松测试 。使用此方法,您将始终使用具有不同请求标头值的相同端点URL来访问不同版本的端点。
为了进行快速测试以确认这是有效的,让我们在标题中调用2.0版本的API
HTTP / 1.1 200 OK
日期:星期四,2018年6月14日08:27:49 GMT
内容类型:text / plain ; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:1.0,2.0
Version 2.0
基于路由的版本控制
基于路由的版本控制基于控制器的url结构,并期望路由包含版本。为此,我们需要将Startup.cs更改为不再从标题中读取,而是查看URL
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1,0);
o.ApiVersionReader = new UrlSegmentApiVersionReader();
});
}
为了支持我们设置为1.0的默认版本,我们还需要为没有版本段的特定版本提供额外的路由,否则默认版本将不起作用
namespace Core.Versioning.Sample.Controllers
{
[ApiVersion("1.0")]
[ApiVersion("1.0", Deprecated = true)]
[Route("api/[controller]")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ValueController : Controller
{
[HttpGet]
public String Get()
{
return "Version 1.0";
}
}
}
namespace Core.Versioning.Sample.Controllers.v2
{
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ValueController : Controller
{
[HttpGet]
public String Get()
{
return "Version 2.0";
}
}
}
现在让我们用curl检查响应
$ curl http:// localhost:5000 / api / value -iHTTP / 1.1 200 OK
日期:星期四,2018年6月14日08:03:34 GMT
内容类型:text / plain; charset = utf-8
服务器:Kestrel
Transfer-Encoding:chunked
api-supported-versions:
1.0,2.0 api-deprecated-versions:1.0Version 1.0
您可能会注意到响应包含api-deprecated-vesion标头密钥设置为1.0。这是因为我们的新控制器具有以下属性
ApiVersion(“1.0”,Deprecated = true)
这告诉Web API客户端不再支持1.0版。如果您的REST服务支持来自不同供应商的多个不同客户端,这可能非常有用。