如何在ASP.NET Core Web Api中完成版本控制

在之前的asp.net web api ,我实现了DefaultHttpControllerSelector来指定我希望请求如何定位我的控制器。 我经常使用不同名称的不同控制器,但用于相同的过程。 唯一的区别是一个版本比另一个版本更高版本。

例如,我可以有一个名为BookingV1Controller的控制器,它将用于处理服务的第一个版本。 我也有BookingV2Controller ,它设计用于处理服务的第二版。 然后,客户端应用程序将使用此URL http://myservice.com/api/v2/booking/someaction?id=12向服务发出请求。 为了处理请求,我将提供DefaultHttpControllerSelector的自定义实现,以根据请求的版本选择所需的控制器的相应版本。

但是,我似乎没有办法在ASP.NET Core执行此操作。 我到处搜索都无济于事。 没有可以帮助的文档。

如果有人能帮助我,我将不胜感激。 谢谢。

更新我还想知道如果在自定义标头中指定版本该怎么办。 例如X-Version:v1

更新2

要求是不应在URL中公开服务的版本。 如果没有版本,则服务返回有关如何添加版本的说明。 如果请求的版本中没有请求的控制器,系统将搜索较低版本。 如果它在任何较低版本中找到它,它就会使用它。 这样做的原因是为了防止在所有版本上重复控制器。 但是使用ASP.NET Core,这可能是不可能的。

在为这个问题敲了几天之后,我正是为此目的创建了一个软件包。 它不需要属性。

https://github.com/GoAheadTours/NamespaceVersioning

总之,您可以在启动文件中注册IApplicationModelConvention,它可以迭代控制器并根据命名空间注册路由。 我创建了一个v1文件夹,并将我的控制器放入其中

实现IApplicationModelConvention的类实现了一个带有ApplicationModel参数的Apply方法,该参数可以访问应用程序中的控制器及其现有路由。 如果我看到控制器没有在我的类中设置路由,则从命名空间获取版本并使用预定义的URL前缀为该版本生成路由。

 public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { var hasRouteAttribute = controller.Selectors.Any(x => x.AttributeRouteModel != null); if (hasRouteAttribute) { continue; } var nameSpace = controller.ControllerType.Namespace.Split('.'); var version = nameSpace.FirstOrDefault(x => Regex.IsMatch(x, @"[v][\d*]")); if (string.IsNullOrEmpty(version)) { continue; } controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel() { Template = string.Format(urlTemplate, apiPrefix, version, controller.ControllerName) }; } } 

我在github上有所有代码,也有nuget上的包的链接

这是我偶然发现的一个非常古老的问题,但现在有更好的解决方案。 有这个包

Microsoft.AspNetCore.Mvc.Versioning

其中有一个function更丰富的实现版本控制的方法。 这些包括能够使用URL查询字符串,URL路径,标题或自定义版本阅读器。 能够从HTTPContext等读取版本

简而言之,您将以下内容添加到startup.cs中的ConfigureServices方法中

 services.AddApiVersioning(o => { o.ReportApiVersions = true; o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = new ApiVersion(1, 0); }); 

然后你必须用ApiVersion装饰你的控制器。

 [ApiVersion("1.0")] [Route("api/home")] public class HomeV1Controller : Controller { [HttpGet] public string Get() => "Version 1"; } [ApiVersion("2.0")] [Route("api/home")] public class HomeV2Controller : Controller { [HttpGet] public string Get() => "Version 2"; } 

您还可以通过将其放入路径中来在路径中实现它。

 [ApiVersion("1.0")] [Route("api/{version:apiVersion}/home")] public class HomeV1Controller : Controller { [HttpGet] public string Get() => "Version 1"; } [ApiVersion("2.0")] [Route("api/{version:apiVersion}/home")] public class HomeV2Controller : Controller { [HttpGet] public string Get() => "Version 2"; } 

当你通过微软软件包实现它实现它的方法时,它也意味着你可以弃用版本,有版本发现,从HttpContext轻松访问版本号等等。如果它是你真的可以做到的只是在你的路线硬编码。

有关详细信息(包括在标题中使用它):

使用路由属性来控制版本。

 [Route("api/v1/[controller]")] public class BookingV1Controller : Controller { .... } [Route("api/v2/[controller]")] public class BookingV2Controller : Controller { .... } 

有关从标准Web Api和.NET Core ASP.NET迁移的更多信息,请参阅: MSDN:从ASP.NET Web Api迁移

为此添加服务API版本到ASP.NET核心应用程序

  public void ConfigureServices( IServiceCollection services ) { services.AddMvc(); services.AddApiVersioning(); // remaining other stuff omitted for brevity } 

QUERYSTRING PARAMETER VERSIONING

 [ApiVersion( "2.0" )] [Route( "api/helloworld" )] public class HelloWorld2Controller : Controller { [HttpGet] public string Get() => "Hello world!"; } 

所以这意味着在另一个具有相同路由的Controller中获得2.0超过1.0,你会去这里:

/api/helloworld?api-version=2.0

我们可以使用不同名称空间的相同控制器名称

URL PATH SEGMENT版本

  [ApiVersion( "1.0" )] [Route( "api/v{version:apiVersion}/[controller]" )] public class HelloWorldController : Controller { public string Get() => "Hello world!"; } [ApiVersion( "2.0" )] [ApiVersion( "3.0" )] [Route( "api/v{version:apiVersion}/helloworld" )] public class HelloWorld2Controller : Controller { [HttpGet] public string Get() => "Hello world v2!"; [HttpGet, MapToApiVersion( "3.0" )] public string GetV3() => "Hello world v3!"; } 

标题版本控制

  public void ConfigureServices( IServiceCollection services ) { services.AddMvc(); services.AddApiVersioning(o => o.ApiVersionReader = new HeaderApiVersionReader("api-version")); } 

当您执行HeaderApiVersioning时,您将无法在浏览器中执行GET,因此我将使用Postman添加标题(或者我可以使用Curl,或WGet,或PowerShell,或unit testing):

图片

请参考https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEasy.aspx