ASP.NET Web API (.NET Core 3.1) 中的端点路由问题

Problem with endpoint routing in ASP.NET Web API (.NET Core 3.1)

下午好,

我在使用属性路由和 ASP.NET 核心路由中间件 API 的网络 API 中遇到端点路由问题。

我有一个 API 控制器,大致如下所示:

public class UsersController : ControllerBase
{
    [HttpGet]
    [Route("v1/users/{id}", Name = nameof(GetUser), Order = 1)]
    public async Task<ActionResult> GetUser([FromQuery(Name = "id")] string userGuid)
    {
       // Implementation omitted.
    }

    [HttpGet]
    [Route("v1/users/me", Name = nameof(GetCurrentUser), Order = 0)]
    public async Task<ActionResult> GetCurrentUser()
    {
        // Implementation omitted.
    }
}

我正在尝试配置端点路由,以便将 'v1/users/me' 的请求路由到 'GetCurrentUser()' 方法,同时请求匹配模板 'v1/users/{id}'(其中 {id} != me) 被路由到 'GetUser()' 方法。我希望这可以通过将 'v1/users/me' 端点放在端点顺序中的另一个端点之前来解决,但路由中间件似乎不遵守顺序参数。我还尝试在映射其余端点之前显式映射 'v1/users/me' 端点,但这似乎也不起作用。

这是当前的启动配置:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
   if (env.IsDevelopment())
   {
       app.UseDeveloperExceptionPage();
   }

   app.UseHttpsRedirection();
   app.UseStaticFiles();
   app.UseResponseCompression();
   app.UseRouting();
   app.UseAuthentication();
   app.UseAuthorization();

   app.UseEndpoints(endpoints =>
   {
       // Explicit mapping of the GetCurrentUser endpoint - doesn't seem to do anything.
       // endpoints.MapControllerRoute("v1/users/me", "Users/GetCurrentUser");

       endpoints.MapControllers();
   }
}

这是否可以通过属性路由实现,如果可以,我还缺少什么?

谢谢!

如果您像这样保留默认值,这应该已经可以正常工作了:

[HttpGet("v1/users/{id}")]
public async Task<ActionResult> GetUser(string id)
{
    return Ok(new { id = id });
}

[HttpGet("v1/users/me")]
public async Task<ActionResult> GetCurrentUser()
{
    return Ok(new { id = "current" });
}

使用属性路由,包含 constant 部分的路由优于在同一位置包含路由变量的路由。因此 v1/users/me 的排名高于 v1/users/{id}id = "me",因此当您访问该路由时,您应该看到 GetCurrentUser 运行。这与控制器中的方法顺序无关。

问题出在 API 端点方法的注释上。

我错误地将 GetUser(string id) 端点中的参数标记为 [FromQuery] 属性而不是 [FromRoute]。

以下按预期工作:

public class UsersController : ControllerBase
{
    [HttpGet]
    [Route("v1/users/{id}", Name = nameof(GetUser))]
    public async Task<ActionResult> GetUser([FromRoute(Name = "id")] string userGuid)
    {
       // Changed from [FromQuery(Name = "id")] to [FromRoute(Name = "id")]

       // Implementation omitted.
    }

    [HttpGet]
    [Route("v1/users/me", Name = nameof(GetCurrentUser))]
    public async Task<ActionResult> GetCurrentUser()
    {
        // Implementation omitted.
    }
}