【问题标题】:ASP.NET Attribute Routes and default routes can work together?ASP.NET Attribute Routes 和 default 路由可以一起工作吗?
【发布时间】:2018-07-04 13:18:22
【问题描述】:

我有一个用 NET Core 2.1 编写的项目,其中我有一堆带有属性路由的控制器/动作。 类似的东西:

[Route("~/test")]
public class ProductsController : Controller
{
    [HttpGet("{id:int}")]
    public IActionResult ById(int id)
    {
        ...
    }
}

在启动时我只是默认设置:

app.UseMvc(routeBuilder =>
{
    routeBuilder.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

因此,应用程序正在按预期解析 /test/42,但无法让 /products/byid?id=42 正常工作...如果我只是注释掉控制器中的属性,则会发生默认路由。

有没有办法让他们一起工作?

【问题讨论】:

    标签: c# asp.net-core asp.net-core-mvc asp.net-core-routing


    【解决方案1】:

    简而言之:将其更改为 [Route("/products")] 并重试。

    详细说明:

    如果您将 RouteAttribute 应用于控制器或操作方法,则该控制器/操作方法将仅响应指定的路由。在您给出的那个特定示例中,它只有在您浏览到 /~test/65 时才会执行。

    如果您希望控制器/操作方法默认使用名称,请尝试使用 [controller][action] 标志,如下所示:

    [Route("[controller]")]
    public class ProductsController : Controller
    {
        [HttpGet("[action]/{id:int}")] // /Products/ById/5
        public IActionResult ById(int id)
        {
            ...
        }
    }
    

    您在 ASP.NET Core 中的默认路由是 MVC 将回退到的路由,如果没有控制器访问您指定的路由。在这种情况下,/Products/ById/5 也可以。

    默认情况下,它映射到Home 控制器和Index 操作方法,这是您的默认主页。如果路由只是/,那么将执行该操作。

    你也可以这样做直接指定你想要的路线

    [Route("/api/products")]
    public class ProductsController : Controller
    {
        [HttpGet("by-id/{id:int}")] // /api/products/by-id/5
        public IActionResult ById(int id)
        {
            ...
        }
    }
    

    您也可以尝试 Joe 尝试过的建议,因为它也是一种方法。但最后你可以微调你的路线,如果你愿意,可以在一个控制器或动作上拥有多条路线。尝试自己进行实验,但请查看文档以了解更多信息。

    很可能,您不想修改默认路由,并根据自己的喜好调整 RouteAttribute。在我提供的链接中了解attribute routingrouting to controller actions using app.UseMvc()

    【讨论】:

    • 我没有考虑标志,但实际上在控制器上添加了 [Route("[controller]")] AND [Route("~/test", Order = 1)] 和[Route("[action]")] AND [HttpGet("{id:int}", Order = 1)] 我得到结果的操作。有点多余,但最后我只为自定义路由下的操作执行此操作。非常感谢!
    • 您可以查看 Joe 消除冗余的答案。文档还提供了一种完全消除冗余的好方法。
    【解决方案2】:

    您可以在同一个应用程序中同时使用属性路由和常规路由。但是,一旦您使用属性路由标记控制器或操作,则根本无法使用常规路由路由到该控制器或操作。您仍然可以为其他控制器使用常规路由。

    如果你希望属性路由使用 /products 那么你可以改变它:

    [Route("~/products")]
    public class ProductsController : Controller
    {
        [HttpGet("{id:int}")]
        public IActionResult ById(int id)
        {
            ...
        }
    }
    

    但您不能将两种类型的路由用于同一个控制器/动作

    我知道的唯一解决方法是您可以创建另一个控制器,该控制器从具有属性路由的控制器继承(使操作方法虚拟)。然后你可以用新的子类控制器去掉属性路由,你可以用常规路由路由到它,只调用基类操作方法。

    例子:

    namespace MyNamespace
    {
        public class ProductsController : Controller
        {
            [HttpGet("{id:int}")]
            public virtual IActionResult ById(int id)
            {
                ...
            }
        }
    }
    
    namespace MyOtherNamespace
    {
    
        public class ProductsController : MyNamespace.ProductsController
        {
    
            public override IActionResult ById(int id)
            {
                base.ById(id);
            }
        }
    }
    

    现在您可以使用常规路由路由到 ProductsController,而基本控制器使用属性路由。

    【讨论】:

    • 我添加了继承控制器的示例
    • 已编辑以显示您可以使用具有不同命名空间的相同控制器类名称
    • 也是一个有效的解决方案,但是需要扩展控制器来覆盖操作有点太难维护了
    • 好的,但另一个答案没有显示如何同时使用属性路由和常规路由,我认为这是您问题的一部分。
    • 但它为我提供了将 [Route("[controller]")] 与我的属性结合使用的线索。正如你们俩所说,最后,他们不应该一起工作,你必须采取某种解决方法
    猜你喜欢
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 2016-01-29
    • 2017-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多