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

时间:2016-04-09 20:57:08

标签: c# rest asp.net-web-api asp.net-core swagger

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

我将展示我是如何陷入困境的,并且我想了解如何修复它。

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

[Route("api/Subscribers/{id}/[controller]")]
[Route("api/Organizations/{id}/[controller]")]
public class AddressesController : Controller
{

    [HttpGet("{aid}", Name = "PostalLink")]
    public async Task<IActionResult> GetAddress(Guid id, Guid aid)
    {
        //...implementation is irrelevant for this question.
    }

    [HttpPost]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.Created, Type = typeof(PostalRecord))]
    public async Task<IActionResult> 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不知道如何解析路由名称&#34; PostalLink&#34;因为它隐含地绑定了两个前缀:

[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可以简单地解决问题&#34;通过它自己。例如,如果当前请求解析为包含单词&#34; Subscribers&#34;的路由,那么&#34; PostalLink&#34;名称应该引用该路线。从这个角度来看,也许我的代码暴露了ASP.NET Core中的错误,缺陷或疏忽。

可能性#2

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

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

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

可能性#3

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

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

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

可能性#4

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

详细

我的project.json配置如下:

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

我使用的是DNX SDK版本1.0.0-rc1-update1。另外,我为那些想要了解我想要做的更多背景的人发布了related SO question

2 个答案:

答案 0 :(得分:1)

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

[Route("api/Subscribers/{id}/[controller]", Name = "SubscriberLink")]
[Route("api/Organizations/{id}/[controller]", Name = "OrganizationLink")]
public class AddressesController : Controller
{

    [HttpGet("{aid}")]
    public async Task<IActionResult> GetAddress(Guid id, Guid aid)
    {
        //...implementation is irrelevant for this question.
    }
}

答案 1 :(得分:0)

您是否研究过属性路由?

例如Registering routes with ASP.Net 5's MVC 6 Attribute Routing

相关documentation中的示例:

  

在下面的示例中,app.UseMvc();方法中使用了Configure,并且没有路由通过。

public class HomeController : Controller
{
   [Route("")]
   [Route("Home")]
   [Route("Home/Index")]
   public IActionResult Index()
   {
      return View();
   }
   [Route("Home/About")]
   public IActionResult About()
   {
      return View();
   }
   [Route("Home/Contact")]
   public IActionResult Contact()
   {
      return View();
   }
}
     

将对任何URL路径HomeController.Index()//Home执行/Home/Index操作。