【问题标题】:Service Fabric Web API Versioning issueService Fabric Web API 版本控制问题
【发布时间】:2021-07-31 16:11:28
【问题描述】:

我正在开发一个包含多个无状态服务的服务结构项目。当我尝试在下面的代码中添加版本控制时

[Authorize]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class SessionController : Controller
{
...
}

稍后使用 Postman 或使用我为调用此服务而制作的某些客户端 winforms 应用程序调用该服务时,它不起作用。当我说它不起作用时,我的意思是它不是在寻找我放置在控制器中的特定版本。

例如 我正在调用 http://localhost:1234/api/v1.0/session/set-session,正如您在我的控制器中看到的那样,我只有 2.0 版。现在,无论我输入什么版本号,我的 API 都会以这种或另一种方式受到影响。

我在 Startup.cs 中添加了代码

services.AddApiVersioning(options => {
       options.DefaultApiVersion = new ApiVersion(2, 0);
       options.AssumeDefaultVersionWhenUnspecified = true;
       options.ReportApiVersions = true;
       options.ApiVersionReader = new HeaderApiVersionReader("x-api-version");
});

具体的 API 调用如下所示:

 [HttpPost]
 [Route("set-session")]
 public async Task<IActionResult> SetSession([FromBody] SessionModel model)
 { ... }

谁能告诉我我缺少什么或者服务结构根本不支持 api 版本控制? 谢谢。

【问题讨论】:

    标签: .net-core asp.net-core-webapi azure-service-fabric api-versioning


    【解决方案1】:

    您的解决方案在本地有效吗?根据我所看到的,我会怀疑 - 不。这应该与 Service Fabric 完全无关。

    问题 1

    我看到你的基类继承自Controller,这是允许的,但通常是ControllerBase。不用担心,仅供参考。问题的症结可能是您的控制器没有应用[ApiController] 属性。 API 版本控制定义了IApiControllerSpecificationIApiControllerFilter,用于过滤哪些控制器应被视为 API。这对于构建混合了 UI 和 API 部分的应用程序的开发人员来说很重要。控制器是 ASP.NET Core 中的控制器,早期很难区分这两者。现在有一个内置的IApiControllerSpecification,它认为任何应用了[ApiController] 的控制器都是一个API。可以使用 ApiVersioningOptions.UseApiBehavior = false 更改、替换或完全禁用它。

    如果您的库/应用程序只有 API,您可以使用以下方法一次性装饰所有控制器:

    [assembly: ApiController]
    

    由于您的控制器当前不被视为 API,因此所有与路由匹配的请求都被定向到那里。值 1.0 被视为任意字符串而不是 API 版本。这就是为什么它完全匹配而不是 HTTP 400。我怀疑你必须只有一个 API,它被定义为 2.0;否则,我会期待AmbiguousActionException

    问题 2

    您的示例显示您正在尝试按 URL 段进行版本控制,但您已将选项配置为仅考虑标头 x-api-version。此选项应配置为以下之一:

    网址段(仅限)

    options.ApiVersionReader = new UrlSegmentApiVersionReader();
    

    URL 段和标头

    // registration order is irrelevant
    options.ApiVersionReader = ApiVersionReader.Combine(
        new UrlSegmentApiVersionReader(),
        new HeaderApiVersionReader("x-api-version"));
    

    默认(查询字符串和 URL 段)

    // NOTE: this is the configuration
    // options.ApiVersionReader = ApiVersionReader.Combine(
    //    new QueryStringApiVersionReader(),
    //    new UrlSegmentApiVersionReader());
    

    旁注

    按照定义,使用 URL 段和标头版本控制方法没有意义。您有一条需要 API 版本的路线。客户端总是必须在每个请求中包含 API 版本,因此没有必要同时支持标头。

    如果你定义了 2 个路由,那么它是有意义的:

    [Route("api/[controller]")]                       // match by header
    [Route("api/v{version:apiVersion}/[controller]")] // match by url segment
    

    按 URL 段进行版本控制虽然很常见,但 RESTful 最少。它违反了 统一接口 约束。这个问题展示了该方法的另一个问题。查询字符串、标头、媒体类型或它们的任何组合都将使用单个路由模板:[Route("api/[controller]")]

    观察 1

    您已配置options.AssumeDefaultVersionWhenUnspecified = true。在按 URL 段进行版本控制时,这将无效。在模板中间提供路由参数的默认值是不可能的。如果未指定 {id}api/value/{id}/subvalues 也是如此。

    如果您满足以下条件,则此选项生效:

    • 添加第二个没有 API 版本参数的路由模板
    • 您将版本控制策略更新为不使用 URL 段

    需要注意的是,这是一个被高度滥用的功能。它旨在祖父在以前没有明确版本控制的现有服务中,因为添加它会破坏现有客户端。如果这不是您的用例,您应该意识到这一点。

    【讨论】:

    • 是的,你对一切都是正确的。我在 Startup.cs 中清除了版本控制配置,并用 [ApiController] 装饰了控制器,效果很好。当我用错误的版本调用 api 时,我得到了 UnsupportedApiVersion 响应,而当调用了正确版本的 api 时,我得到了正确的响应。非常感谢伙计。我会投票给这个答案作为正确的答案,但由于我的声誉不足,其他人无法看到它。
    猜你喜欢
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 2018-07-11
    相关资源
    最近更新 更多