简体   繁体   English

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

[英]Route Disambiguation in ASP.NET Core (MVC 6)

When ASP.NET Core encounters ambiguously named routes, it becomes inert. 当ASP.NET Core遇到模糊命名的路由时,它变得惰性。 That is, the application will run without exceptions thrown but, it will fail to process any requests, on any controllers. 也就是说,应用程序将在没有抛出异常的情况下运行,但是,它将无法在任何控制器上处理任何请求。 The calling client receives 500 responses. 主叫客户端收到500个响应。

I'll show how I got into this mess, and I'd like suggestions of how to fix it. 我将展示我是如何陷入这个烂摊子的,我想知道如何修复它。

I have a controller that looks like this: 我有一个看起来像这样的控制器:

[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 });
    }

Why the two route prefixes on the controller? 为什么控制器上有两个路由前缀? Because it fits my microservices (and Swagger documentation) strategy. 因为它适合我的微服务(和Swagger文档)策略。 Nevertheless, in this example ASP.NET Core does not know how to resolve the route name "PostalLink" because it is implicitly bound to the two prefixes: 然而,在此示例中,ASP.NET Core不知道如何解析路由名称“PostalLink”,因为它隐式绑定到两个前缀:

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

I can fix the problem simply by changing the HttpGet so that instead of this: 我可以通过更改HttpGet来解决问题,而不是这样:

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

I have this: 我有这个:

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

Unfortunately, removing the route name is not a real option for me. 不幸的是,删除路由名称对我来说不是一个真正的选择。

What is the prescribed way to fix this? 解决这个问题的规定方法是什么?

Below are some of the options I'm considering. 以下是我正在考虑的一些选项。

Possibility #1 可能性#1

Theoretically, ASP.NET could simply "figure it out" by itself. 从理论上讲,ASP.NET可以简单地“弄清楚”自己。 For example, if the current request resolved to the route containing the word "Subscribers", then the "PostalLink" name should reference that route. 例如,如果当前请求解析为包含单词“Subscribers”的路由,则“PostalLink”名称应引用该路由。 Seen this way, perhaps my code is exposing a bug, defect, or oversight in ASP.NET Core. 从这个角度来看,也许我的代码暴露了ASP.NET Core中的错误,缺陷或疏忽。

Possibility #2 可能性#2

I could collapse my two prefix routes into a single route like this: 我可以将我的两个前缀路由折叠成一条路由,如下所示:

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

This works, but it undermines my REST documentation strategy. 这有效,但它破坏了我的REST文档策略。 I'm using Swashbuckle to publish endpoint metadata. 我正在使用Swashbuckle发布端点元数据。 I want a user of my API to expressly see that my "Addresses" API is serving either "Subscribers" or "Organizations". 我希望我的API用户明确地看到我的“地址”API正在为“订阅者”或“组织”提供服务。 When I have two explicit route prefixes, the Swagger documentation works correctly (and I properly validate the URI used by the client). 当我有两个显式路由前缀时,Swagger文档正常工作(并且我正确验证了客户端使用的URI)。

Possibility #3 可能性#3

I could simply override the two prefixes like this: 我可以简单地覆盖这两个前缀:

    [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.
    }

Now my documentation and route validation works, but my implementation is forced to check which route was used to reach the endpoint. 现在我的文档和路由验证工作,但我的实现被迫检查用于到达端点的路由。 That is very doable, but very annoying. 这是非常可行的,但非常烦人。

Possibility #4 可能性#4

Perhaps there is a more expressive way to handle this problem without attribute-based-routing? 也许有一种更有表现力的方法来处理这个问题而没有基于属性的路由? If yes, please share! 如果是,请分享!

Details 细节

My project.json is configured as follows: 我的project.json配置如下:

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

I am using DNX SDK version 1.0.0-rc1-update1. 我使用的是DNX SDK版本1.0.0-rc1-update1。 Also, I posted a related SO question for those who would like more context of what I am trying to do. 此外,我发布了一个相关的SO问题,以便那些想要了解我想要做的更多背景的人。

If your route names are the same for all your actions, why not specify them directly on the controller ? 如果您的所有操作的路径名称相同,为什么不直接在控制器上指定它们?

[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.
    }
}

Have you looked into attribute routing? 你看过属性路由了吗?

Eg Registering routes with ASP.Net 5's MVC 6 Attribute Routing 例如, 使用ASP.Net 5的MVC 6属性路由注册路由

Sample from the relevant documentation : 相关文件中的样本:

In the following example, app.UseMvc(); 在以下示例中, app.UseMvc(); is used in the Configure method and no route is passed. 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(); } } 

The HomeController.Index() action will be executed for any of the URL paths / , /Home , or /Home/Index . 将对任何URL路径//Home/Home/Index执行HomeController.Index()操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM