在.NET Core中,相同控制器的多个带版本和不带版本的路由不起作用。

huangapple go评论51阅读模式
英文:

Multiple routes with and without version for the same controller in .NET Core is not working

问题

我想创建两个路由,一个带有版本信息,另一个不带版本信息,指向相同的控制器而不装饰控制器方法。

我已经在控制器顶部定义了两个路由,但是使用这两个路由发送请求会导致500内部服务器错误。

我有以下代码片段:

[ApiController]
[Route("api/docs")]
[Route("api/v1.0/docs")]
public class DocsController : ControllerBase
{
    // . . . .

    [HttpGet]
    public async Task<IActionResult> GetAsync( . . .)
    { . . }
}

我正在寻找一种方法让控制器对这两个路由做出相同的响应。有什么方法可以实现这一点?

英文:

I want to create two routes, one with version and another without, to point to the same controller without decorating the controller methods.

I have defined two routes at the top of the controller, but sending requests using both routes results in 500 Internal server error.

I have the following code snippets:

[ApiController]
[Route(&quot;api/docs&quot;)]
[Route(&quot;api/v1.0/docs&quot;)]
public class DocsController : ControllerBase
{
    // . . . .

    [HttpGet]
    public  async Task&lt;IActionResult&gt; GetAsync( . . .)
    { . . }
}

I am looking a way to make the controller to respond the same for both routes. What are some ways to achieve this?

答案1

得分: 1

一些具体的错误细节将会很有用。出于安全原因,这些信息很可能不会通过网络传输 - 你不应该启用它。你的日志基础设施,无论是针对某个外部源或者只是在调试时输出到控制台,都应该提供非常详细的信息,以解释问题的原因。500 通常是未处理异常的结果,这肯定会被平台记录下来。

在没有其他信息的情况下,我的第一个猜测也是最好的猜测是问题与你的操作名称有关: GetAsync。除非你确实需要它并了解其影响,否则应该去掉 Async 后缀。在 ASP.NET Core 3.0 中不再支持该后缀,这是一个重大变更。如果你刚刚在升级或不了解这个变更,很容易受到影响:

重大变更:控制器操作名称中删除了 Async 后缀

"双重路由注册" 绝对是可能的,并得到支持。这是我所知道的在通过 URL 段进行版本控制时具有隐式和显式路由模板的唯一方式。通过 URL 段进行版本控制不是我推荐的做法。随着服务的成熟,它会带来许多问题,而且它不符合 "统一接口" 约束。这是一种流行的方法,但要知道 "那里有风险"。选择权在你手中。

如果你想为你的 ASP.NET Core API 添加版本控制,我建议你考虑使用 ASP.NET Core API Versioning。你要找的包是 Asp.Versioning.Mvc (请注意,它已从较旧的 Microsoft.AspNetCore.Mvc.Versioning 更名而来)。还有一些 示例项目,展示了各种端到端的配置。

根据你目前提供的信息,有多种方法可以配置你的应用程序,但基于你目前提供的信息,这是我的建议:

[ApiVersion(1.0)]
[ApiController]
[Route("api/[controller]")]
[Route("api/v{version:apiVersion}/[controller]")]
public class DocsController : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> Get(CancellationToken cancellationToken)
    {
        await Task.Yield();
        return Ok();
    }
}

在你的应用程序设置中,你应该添加以下配置:

services.AddApiVersioning(
          options =>
          {
              // 允许没有 API 版本的请求;
              // 例如,~/api/docs
              //
              // 注意: 谨慎使用。这仅用于支持向后兼容性
              options.AssumeDefaultVersionWhenUnspecified = true;
          })        // ← 添加最小的 API 版本支持
         .AddMvc(); // ← 添加带有控制器版本支持的 MVC 核心

如果这不完全回答了你的问题,或者你有其他问题,我很乐意提供进一步的解释。你可以提供任何其他上下文或细节将会很有用。

声明: 我是 ASP.NET API Versioning 项目的所有者。

英文:

Some specific error details would be useful. The information very well may not be transmitted over the wire for security reasons - and you should never enable that. Your logging infrastructure, be it to some external source or just the console while debugging, should have very detailed information explaining the cause of the problem. A 500 is generally the result of an unhandled exception, which would definitely be logged by the platform.

Without any other information, my first and best guess is that the problem is related to your action name: GetAsync. You should drop the Async suffix unless you really, really want it and understand the ramifications of that. The support for that suffix was dropped in ASP.NET Core 3.0 and is a breaking change. If you happened to just now be upgrading or didn't know about this change, it's really easy to get bitten by:

Breaking Change: Async suffix trimmed from controller action names

Double-Route Registration is definitely possible and supported. It's the only way I know of have an implicit and explicit route template when you version by URL segment. Versioning by URL segment is not something I recommend. It's littered with issues as your service matures and it's not RESTful; it violates the Uniform Interface constraint. It's a popular approach, but know that there be dragons. That choice is in your hands.

If you're looking to add versioning to your ASP.NET Core APIs, might I suggest that you consider ASP.NET Core API Versioning. The package you are looking for is Asp.Versioning.Mvc (note: that it has changed from the older Microsoft.AspNetCore.Mvc.Versioning). There are also several example projects that illustrate various configurations end-to-end.

There are multiple ways that you can configure your application, but based on what you have provided thus far, this is what I would suggest:

[ApiVersion(1.0)]
[ApiController]
[Route(&quot;api/[controller]&quot;)]
[Route(&quot;api/v{version:apiVersion}/[controller]&quot;)]
public class DocsController : ControllerBase
{
    [HttpGet]
    public async Task&lt;IActionResult&gt; Get(CancellationToken cancellationToken)
    {
        await Task.Yield();
        return Ok();
    }
}

In your application setup, you would add the following configuration:

services.AddApiVersioning(
          options =&gt;
          {
              // allows requests without an api version;
              // for example, ~/api/docs
              //
              // note: use with caution. this is ONLY meant to be used
              // to support backward compatibility
              options.AssumeDefaultVersionWhenUnspecified = true;
          })        // ← adds minimal api versioning support
         .AddMvc(); // ← add mvc core with controllers versioning support

I'm happy to elaborate further if this does not fully answer your question or you have additional questions. Any other context or details you can provide would be useful.

>Disclaimer: I am the owner of the ASP.NET API Versioning project

huangapple
  • 本文由 发表于 2023年3月9日 18:34:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75683393.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定