【问题标题】:Prevent default attribute routing behaviour when no route attribute is specified on a controller method当控制器方法上没有指定路由属性时,防止默认属性路由行为
【发布时间】:2021-01-21 02:30:25
【问题描述】:

在 ASP.NET Core 5.0 应用中仅使用属性路由时,例如,Startup 中的以下内容:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

具有单个公共方法且没有路由属性的控制器类仍将匹配GET 请求,否则该请求将匹配该控制器。

例如GET api/test 将匹配下面的Index 方法(调用什么方法无关紧要),即使该方法没有路由属性:

[ApiController]
[Route("api/[controller]")]
public class TestController
{
    public IActionResult Index()
    {
        return Ok();
    }
}

但是,如果将另一个公共方法添加到该控制器类,同样没有属性,则会为 GET api/test 抛出 AmbiguousMatchException,因为路由无法确定要使用哪个方法。

如果将[HttpGet] 属性添加到这些方法之一,则问题得到解决。

我了解一种解决方案是确保所有方法都具有适当的路由属性,或者控制器上只有一种方法是公共的。

有没有办法防止这种默认/回退行为仍然匹配没有显式属性的方法?

属性路由是否可以配置为仅匹配具有显式路由属性的方法?

【问题讨论】:

  • 我现在无法检查,但我想您可以在 app.UseRouting(); 调用 Startup.Configure 方法之后添加一些自定义中间件。类似this
  • 也许你可以用IActionDescriptorProvider做点什么

标签: c# asp.net-core


【解决方案1】:

将路线设置为:

[Route("api/{controller}/{action}")] 

将指示必须指定操作,除非您像这样指定默认操作,否则它不会默认为任何内容:

[Route("api/{controller}/{action=Index}")] 

编辑:

如果你想强制明确路由,那么你可以从控制器级别删除 [Route()] 属性并将其添加到每个操作之上

[ApiController]
public class TestController
{
    [Route("api")]
    [Route("api/[controller]")]
    [Route("api/[controller]/index")]
    public IActionResult Index()
    {
        return Ok();
    }

    [Route("api/[controller]/asdf")]
    [Route("api/[controller]/asdf/{id?}")]
    public IActionResult Index2(int? id)
    {
        return Ok();
    }
}

除非每个操作都具有 Route() 属性或其他类似属性,如 HttpGet()、HTTpPost() 等,否则代码将无法编译。

【讨论】:

  • 谢谢马特。这确实有效,并且是解决症状的一种更优雅的方式,但是,我有点希望找到一种解决方案,禁用未修饰方法的匹配;该解决方案实际上只是确保路由器选择了正确的未修饰方法。这可能是 ASP.NET Core 开发人员想要的唯一方法,所以除非很快出现另一个更具体的答案,否则我会接受这个。
  • 我不明白您的最终目标是什么,您所描述的基本上是没有将控制器映射到路线。如果控制器操作没有映射到路由并且无法到达,为什么还需要控制器操作?你考虑过 endpoints.Map() 函数吗?
  • 我只是在寻找一种方法来关闭(不是解决方法)这种看似后备的行为。变通办法会产生意想不到的后果,例如您的解决方案在方法上打破了其他路线,例如[HttpGet("{id}")]。正如我(有点)在我的问题中所说,一种解决方案是在控制器上没有公共方法。但是,例如(正如我遇到的那样),如果有人向控制器继承的基类添加公共方法,那么它会突然破坏所有控制器。除非我要求,否则感觉不应该发生这种情况。我宁愿它 require [HttpGet] 或给 404。
  • [HttpGet("{id}")] 注释的动作将在/api/test/<actionname>/3 处执行。如果您真的想明确每条路线,那么您可以从控制器中删除该语句并在每个动作上方进行注释,在这种情况下,如果您添加另一个动作并且不会对其进行注释,代码将无法编译。
  • 您关于删除控制器级别注释的评论是最合适的。这确保了所有路由都被明确定义,并防止无意中引入意外行为。您想更新您的答案以包含此内容吗?
猜你喜欢
  • 2016-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
相关资源
最近更新 更多