【问题标题】:ASP.NET Core routing engine confusionASP.NET Core 路由引擎混淆
【发布时间】:2019-09-13 20:36:01
【问题描述】:

我正在尝试创建一个可靠的示例来说明 ASP.NET Core 路由引擎的工作原理,结果令我感到惊讶。

本示例背后的前提是点击控制器索引页面,然后使用 AJAX 请求加载数据。

我使用 MVC 创建了一个 ASP.Net Core 应用程序。然后我添加了以下Controller:

namespace WebApplication2.Controllers {
    using Microsoft.AspNetCore.Mvc;

    public class SearchController : Controller {
        public IActionResult Index() {
            return View();
        }

        [HttpGet("{company}")]
        public IActionResult Get(string company) {
            return Ok($"company: {company}");
        }

        [HttpGet("{country}/{program}")]
        public IActionResult Get(string country, string program) {
            return Ok($"country: {country} program: {program}");
        }
    }
}

我还创建了一个简单的视图来与带有“搜索页面”字样的索引一起使用,以便您可以看到它被调用。

问题是由此创建的路由没有意义。

预期结果

  • /搜索/索引
  • /搜索/{公司}
  • /搜索/{国家/地区}/{程序}

以公司:“Abc”,国家:“加拿大”和项目:“Plumbing”为例:

  • /搜索/索引

    产生:“搜索页面”

  • /搜索/Abc

    产生“公司:Abc”

  • /搜索/加拿大/水暖

    产生:“国家:加拿大程序:管道”

实际结果

但是它根本不像这样工作。相反,这些是结果:

  • /搜索/索引

产生:“国家:搜索程序:索引”

  • /搜索/Abc

产生:“国家:搜索程序:Abc”

  • /搜索/加拿大/水暖

产生:404 未找到

显然 Index 和 Get string company 的路由混淆了,它把 Controller 的名字当作参数。

我可以使用以下代码使其工作,但我认为路由引擎会产生相同的结果:

    public class SearchController : Controller {
        public IActionResult Index() {
            return View();
        }

        [HttpGet("[controller]/{company}")]
        public IActionResult Get(string company) {
            return Ok($"company: {company}");
        }

        [HttpGet("[controller]/{country}/{program}")]
        public IActionResult Get(string country, string program) {
            return Ok($"country: {country} program: {program}");
        }

我的理解有什么问题?必须明确指定[controller] 似乎很愚蠢。

【问题讨论】:

  • 将基本路由添加到 SearchController 类似这样的 [Route("api/[controller]")] SearchController
  • 要使用约定基路由,需要在启动文件中添加app.UseMvc(routes => { routes.MapRoute(template: "{controller}/{action}");});

标签: c# asp.net-core


【解决方案1】:

您将常规路由和属性路由混合在一起,而您不应该这样做。

对于您的原始代码,当您删除 url 中的所有 /Search 时,它将起作用。

要使用控制器名称,您需要在 mvc 控制器上设置 [Route("[controller]")] 以使您的 url 按预期工作。

[Route("[controller]")]
public class SearchController : Controller
{
    [HttpGet("[action]")]
    public IActionResult Index()
    {
        return View();
    }

    [HttpGet("{company}")]
    public IActionResult Get(string company)
    {
        return Ok($"company: {company}");
    }

    [HttpGet("{country}/{program}")]
    public IActionResult Get(string country, string program)
    {
        return Ok($"country: {country} program: {program}");
    }
}

【讨论】:

  • 所以我的问题是我希望 ASP.NET Core 路由引擎通过为控制器指定路由来自动执行此操作。将[Route("[controller]")] 添加到我创建的所有控制器中是否是一种好习惯,或者我应该谨慎地这样做?
  • @Jelf 在我看来,属性路由是比约定路由更灵活的解决方案。您可以将它用于所有控制器,但如果您为特定控制器使用属性路由,则传统路由将不起作用。
【解决方案2】:

指定类上方的根路由

[Route("Search")]
public class SearchController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpGet("{company}")]
    public IActionResult Get(string company)
    {
        return Ok($"company: {company}");
    }

    [HttpGet("{country}/{program}")]
    public IActionResult Get(string country, string program)
    {
        return Ok($"country: {country} program: {program}");
    }
}

【讨论】:

  • 这不是应该暗示的吗?
  • 如何推断您希望将路线称为“搜索”?如何推断您不希望这些路由脱离根目录?除非您指定,否则它将把端点视为脱离根。因此,这些端点将位于 ip:port/ 下,而不是 ip:port/Search/
【解决方案3】:

Routing 负责将请求 URL 映射到端点,它带有两种类型的 Conventional 和 Attributes 路由。

从您的问题来看,您期望使用默认路由的常规路由,您可以使用下面的代码行在 .NET CORE 中实现。

app.UseMvc(routes =>
{
    routes.MapRoute("default", "{controller=Search}/{action}/{id?}");
});

注意:但请记住,如果您使用 [ApiController] 属性装饰控制器,常规路由将不起作用。

默认情况下,.NET CORE 支持属性路由,因此您必须通过将 [Route] 属性放置在控制器级别来为路由添加前缀。请看下面的例子

[Route("api/[controller]")]
    [ApiController]
    public class SearchController : ControllerBase
    {
        
    [HttpGet("{company}")]
    public IActionResult Get(string company) {
        return Ok($"company: {company}");
    }

    [HttpGet("{country}/{program}")]
    public IActionResult Get(string country, string program) {
        return Ok($"country: {country} program: {program}");
    }
   }

上面的代码会按照你的预期工作。

如果您通过 [ApiController] 属性来装饰控制器,那么您必须使用属性路由,并且启动类中定义的任何常规路由都将被覆盖。更多详情请查看here

【讨论】:

    猜你喜欢
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2014-02-12
    • 1970-01-01
    相关资源
    最近更新 更多