c# - ASP.NET Core API 版本控制具有 Major.minor 但仅在路径中包含 Major

标签 c# .net asp.net-web-api api-versioning

有没有办法实现以下目标:

  • Controller 使用 ma​​jor.minor 模式通过 ApiVersionAttribute 进行版本控制,因此 1.12.3 等等
  • 相应的路由仅包含路径中的主要部分,例如/v1/WeatherForecast

我尝试将如下内容添加到为 ASP.NET Core Web API (.NET 6) 创建的默认项目中。

WeatherForecastController.cs:

[ApiController]
[ApiVersion("1.1")]
[Route("v1/[controller]")]
public class WeatherForecastController : ControllerBase
{
}

Program.cs

builder.Services.AddApiVersioning(
    options =>
    {
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;
    });

现在我无法调用端点/v1/WeatherForecast,我收到错误:

{
    "error": {
        "code": "UnsupportedApiVersion",
        "message": "The HTTP resource that matches the request URI 'https://localhost:7170/v1/WeatherForecast' is not supported.",
        "innerError": null
    }
}

谢谢

最佳答案

听起来就像您可能将API版本版本的某些内部服务器概念混为一谈。 API 版本是您契约(Contract)的一部分。

根据设计,客户端不能请求 1.0,而是获取 1.1。这对客户来说是一种误导和困惑。作为服务器,您不能从客户端下面拉出地毯并期望它不会破坏客户端(除非您拥有两侧)。 向后兼容是一个谬论。服务器无法保证添加或删除数据属性不会破坏客户端。 可能不会,但你不能保证。

上面没有任何内容匹配的原因是 API 版本控制不会对您的路由模板做出任何假设或推理。如果您想要 URL 路径中的版本(不是 RESTful),那是您的选择,但您必须按照 @kanils_ 建议在模板中使用路由约束。它应该看起来像:

[ApiController]
[ApiVersion("1.1")]
[Route("v{version:apiVersion}/[controller]")]
public class WeatherForecastController : ControllerBase
{
}

您可以随意调用该参数,但通常使用 version。现在这将启用 https://localhost:7170/v1.1/WeatherForecast1.0 没有定义,因此 v1 将无法解析。

options.AssumeDefaultVersionWhenUnspecified = true 不会执行您认为它会执行的操作(很可能)。这是一个被严重滥用的功能。它的目的是在现有 API 正式提供正式版本之前支持其祖父。此行为只存在于一个版本中。如果不支持此功能,则所有不知道在请求中包含版本的现有客户端都会中断。路由模板不能有默认路由参数值,除非它位于模板的末尾。这意味着除非在 URL 中指定 API 版本,否则模板将永远匹配。通过 URL 段进行版本控制是唯一存在此问题的方法。

我不认可、同意或建议使用除显式 API 版本之外的任何内容,但这可以发挥作用。如果客户端请求 application/json 并希望它被理解,您就不会返回 application/xml。 API 版本也不异常(exception)。由于您是通过 URL 段进行版本控制,因此这将需要双重路由注册。您需要一条中性路线作为捕获所有和每条特定路线。这将为那些想要稳定的东西的客户提供一个明确的 URL,并为其他所有东西提供一个 float 路由。如果一条路线是客户的移动目标,那么老实说,在我看来,它并不比没有版本控制好。

开头:

namespace V1
{
  [ApiController]
  [ApiVersion("1.0")]
  [Route("v{version:apiVersion}/[controller]")]
  public class WeatherForecastController : ControllerBase
  {
  }
}

namespace V1_1
{
  [ApiController]
  [ApiVersion("1.1")]
  [Route("[controller]")] // ← 2nd 'floating' route template
  [Route("v{version:apiVersion}/[controller]")]
  public class WeatherForecastController : ControllerBase
  {
  }
}

在配置中添加:

builder.Services.AddApiVersioning(
    options =>
    {
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;

        // OPTION 1: explicitly set the default value;
        //           this is the 'assumed' version by default.
        //           the default value is new ApiVersion(1.0)
        //
        // options.DefaultApiVersion = new ApiVersion(1.1);

        // OPTION 2: most people using this setup want to 'float'
        //           an API to the most current version available
        //
        options.ApiVersionReader =
            new CurrentImplementationApiVersionSelector(options);
    });

当客户端请求 WeatherForecast 时,请求将定向到与 v1.1/WeatherForecast 相同的位置。这是因为:

  • 未从模板中解析任何 API 版本
  • AssumeDefaultVersionWhenUnspecified = true
  • CurrentImplementationApiVersionSelector1.1 解析为该 API 的当前(例如最高)可用版本

当您最终添加新版本(例如 1.22.0)时,您将必须移动 float [Route("[controller]") ] 将模板从旧的当前 Controller 路由到新的 Controller 。可能有更方便的方法来管理它,但这种方法肯定有效。

由于文字 /v1 未知或无法被 API 版本控制识别,因此您可能可以将其与此方法结合使用,并且它会起作用,但恕我直言,这是一个令人头疼的问题.

在所有这些配置中,您不能(也不应该)消除显式路由,但您可以实现隐式路由目标。缺少文档可能会隐藏它们。

关于c# - ASP.NET Core API 版本控制具有 Major.minor 但仅在路径中包含 Major,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74235911/

相关文章:

c# - iTextsharp 横向文档

c# - 从 IList<> 返回 ReadOnlyCollection

c# - 每个用户的 WebApi OData 属性安全性

c# - 使用 SQLiteDataReader 的异常

c# - 匿名函数的强制参数评估

c# - webrequest 和 httpwebrequest 有什么区别

.NET Web API 2 和 IIS PUT/DELETE 不工作

c# - Angular 2 Http 删除 header 以便与 Web API REST 一起使用

c# - Gridview 中的 DataBind 用户控件

C# 和 C++,从 C# 调用 C++ dll 时出现运行时错误