ASP.NET Core中的路由消歧(MVC 6)

当ASP.NET Core遇到含糊不清的命名路由时,它变得惰性。 也就是说,应用程序将在没有抛出exception的情况下运行,但是,它将无法在任何控制器上处理任何请求。 主叫客户端收到500个响应。

我将展示我是如何陷入这个烂摊子的,我想知道如何修复它。

我有一个看起来像这样的控制器:

[Route("api/Subscribers/{id}/[controller]")] [Route("api/Organizations/{id}/[controller]")] public class AddressesController : Controller { [HttpGet("{aid}", Name = "PostalLink")] public async Task GetAddress(Guid id, Guid aid) { //...implementation is irrelevant for this question. } [HttpPost] [SwaggerResponseRemoveDefaults] [SwaggerResponse(HttpStatusCode.Created, Type = typeof(PostalRecord))] public async Task CreateAddress(Guid id, [FromBody] PostalAddress address) { address.ID = Guid.NewGuid(); await createAddress.Handle(address); return CreatedAtRoute("PostalLink", new { id = id, aid = address.ID }); } 

为什么控制器上有两个路由前缀? 因为它适合我的微服务(和Swagger文档)策略。 尽管如此,在此示例中,ASP.NET Core不知道如何解析路由名称“PostalLink”,因为它隐式绑定到两个前缀:

 [Route("api/Subscribers/{id}/[controller]")] [Route("api/Organizations/{id}/[controller]")] 

我可以通过更改HttpGet来解决问题,而不是这样:

  [HttpGet("{aid}", Name = "PostalLink")] 

我有这个:

  [HttpGet("{aid}")] //the route is no longer "named" 

不幸的是,删除路由名称对我来说不是一个真正的选择。

解决这个问题的规定方法是什么?

以下是我正在考虑的一些选项。

可能性#1

从理论上讲,ASP.NET可以简单地“弄清楚”自己。 例如,如果当前请求解析为包含单词“Subscribers”的路由,则“PostalLink”名称应引用该路由。 从这个角度来看,也许我的代码暴露了ASP.NET Core中的错误,缺陷或疏忽。

可能性#2

我可以将我的两个前缀路由折叠成一条路由,如下所示:

 [Route("api/{parent}/{id}/[controller]")] 

这有效,但它破坏了我的REST文档策略。 我正在使用Swashbuckle发布端点元数据。 我希望我的API用户明确地看到我的“地址”API正在为“订阅者”或“组织”提供服务。 当我有两个显式路由前缀时,Swagger文档正常工作(并且我正确validation了客户端使用的URI)。

可能性#3

我可以简单地覆盖这两个前缀:

  [HttpGet("~/api/Subscribers/{id}/Addresses/{aid}", Name = "SubscriberLink")] [HttpGet("~/api/Organizations/{id}/Addresses/{aid}", Name = "OrganizationLink")] public async Task GetAddress(Guid id, Guid aid) { //...implementation is irrelevant for this question. } 

现在我的文档和路由validation工作,但我的实现被迫检查用于到达端点的路由。 这是非常可行的,但非常烦人。

可能性#4

也许有一种更有表现力的方法来处理这个问题而没有基于属性的路由? 如果是,请分享!

细节

我的project.json配置如下:

 "frameworks": { "dnx46": { } }, 

我使用的是DNX SDK版本1.0.0-rc1-update1。 此外,我发布了一个相关的SO问题,以便那些想要了解我想要做的更多背景的人。

如果您的所有操作的路径名称相同,为什么不直接在控制器上指定它们?

 [Route("api/Subscribers/{id}/[controller]", Name = "SubscriberLink")] [Route("api/Organizations/{id}/[controller]", Name = "OrganizationLink")] public class AddressesController : Controller { [HttpGet("{aid}")] public async Task GetAddress(Guid id, Guid aid) { //...implementation is irrelevant for this question. } }