七、路由

路由是 ASP 中重要的概念之一.NET MVC 应用,因为它负责处理传入的请求并将它们映射到适当的控制器操作。

在本章中,我们将学习以下主题:

  • 使用MapRoute方式配置路由
  • 带有示例的不同类型的路由-约定的和基于属性的
  • 在基于属性的路由中使用 HTTP 动词

我们在第 3 章、控制器中简要讨论了路由。 在本章中,我们将讨论路由以及在 ASP 中定制路由的几种可用选项。 净的核心。

基于约定的路由

路由引擎负责将传入请求映射到控制器的适当操作方法。

Startup类的Configure方法中,我们映射了以下路径:

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

MapRoute方法有两个参数:

  • name:表示路由的名称,因为我们可以为同一个应用配置多条路由。
  • template:表示路由的实际配置。 这个配置值有三个部分。 由于我们提供了默认参数,如果没有传递值,它将接受默认参数值。
  • {controller=Employee}:第一个值作为控制器的名称,当控制器的值在 URL 中不可用时,我们使用Employee控制器作为默认控制器。
  • {action=Index}:Index动作方法将作为默认的动作方法,URL 中的第二个参数将作为动作方法的名称。
  • {id?``}:通过在id参数后指定“?”,我们表示id是可选参数。 如果该值作为第三个参数传递,则将采用id值。 否则,它将不被考虑。

还有另一种方法具有相同的功能。 app.UseMvcWithDefaultRoute()方法配置路由"{controller=Employee}/{action=Index}/{id?}"。 但是我们已经使用了前面的方法来说明我们可以根据自己的需要定制路由。

让我们看几个例子并观察路由引擎是如何工作的。 对于前面的例子,我们假设下面的路由:

"{controller=Employee}/{action=Index}/{id?}" 

例 1

网址-http://localhost:49831/

在此 URL 中,我们没有为controlleractionid传递值。 因为我们没有传递任何东西,所以它将采用控制器和动作的默认值。 因此,路由引擎将 URL 转换为以下 URL:

http://localhost:49831/Employee/Index

示例 2

网址-http://localhost:49831/Employee/

在此 URL 中,我们传递了controller(第一个参数)的值,即Employee,而没有传递action方法(第二个参数)或id方法(第三个参数)的任何内容。 因此,通过取action方法的默认值,将 URL 转换为以下 URL:

http://localhost:49831/Employee/Index

示例 3

网址-http://localhost:49831/Manager/List

路由引擎将第一个参数Manager作为controller方法名,第二个参数List作为action方法名。

示例 4

网址-http://localhost:49831/Manager/Details/2

我们已经在这个 URL 中传递了所有三个参数。 因此,第一个参数值Manager将被视为controller方法名,第二个参数值将被视为action方法名,第三个参数值将被视为id方法名。

在定义地图路径时,我们使用了带有几个参数的MapRoute方法。 第一个参数name表示路由的名称,第二个参数template表示要匹配的 URL 模式和默认值:

routes.MapRoute(name: "default",
               template: "{controller=Employee}/{action=Index}/{id?}");

这个MapRoute方法还有其他重载的变体。 下面是另一个常用的重载MapRoute方法,其中传入的 URL 模式和默认值将用于不同的参数。 路由的名称为FirstRoute,该路由将应用于所有以Home开头的 url。 控制器和动作的默认值分别为HomeIndex2:

routes.MapRoute(name:"FirstRoute",
               template:"Home",
               defaults:new {controller ="Home", action="Index2"});

您可以为您的 ASP 定义任意数量的路由映射。 净 MVC 应用。 对路由图没有限制或限制。 让我们向应用添加另一个路由映射。 我们在应用中添加了另一个名为FirstRoute的路线图(用粗体突出显示):

public void Configure(IApplicationBuilder app) 
    { 
        app.UseIISPlatformHandler(); 
        app.UseMvc(routes => 
        { 

routes.MapRoute(name:"FirstRoute",
            template:"Home", defaults:new {controller ="Home", action="Index2"}); 

            routes.MapRoute(name: "default",
            template: "{controller=Employee}/{action=Index}/{id?}");
        }); 
    } 

我们还添加了另一个名为HomeControllercontroller方法,其中有两个简单的action方法返回不同的字符串:

public class HomeController : Controller 
    { 
        // GET: /<controller>/ 
        public IActionResult Index() 
        { 
            return Content("Index action method"); 
        } 

        public IActionResult Index2() 
        { 
            return Content("Index2 action method"); 
        } 
    } 

当您试图通过 URLhttp://localhost:49831/Hello访问应用时,路由映射FirstRoutedefault都与 URL 模式匹配。

您认为在这个场景中会应用哪种映射路由?

路由引擎根据以下因素映射传入的 URL:

  1. 匹配模式。
  2. 按照路由引擎中定义的顺序。

第一个因素很明显。 为了让路由引擎获取路由映射,传入 URL 的模式应该与路由映射中定义的模板匹配。

第二个因素很微妙但很重要。 如果有多个路由映射与传入的 URL 匹配,路由引擎将选择配置中定义的第一个 URL。 例如,如果传入的 URL 同时匹配FirstRoutedefault映射,路由引擎将选择在配置中首先定义的FirstRoute映射。

Example 4

如果路由引擎不能将传入的 URL 映射到任何映射路由,我们将得到一个HTTP 404 error,这意味着无法找到资源。 通过查看开发工具中的Network选项卡,可以看到状态(200 表示OK,404 表示未找到资源),如下图所示:

Example 4

基于属性的路由

到目前为止,我们一直使用基于约定的路由。 在基于约定的路由中,我们将路由模板(只是参数化的字符串)定义在一个集中的位置,这些模板适用于所有可用的控制器。 基于约定的路由的问题在于,如果我们想为不同的控制器定义不同的 URL 模式,我们需要定义一个对所有控制器都通用的自定义 URL 模式。 这使得事情变得困难。

还有另一个选项可以配置基于属性的路由引擎。 在基于属性的路由中,不是在一个集中的位置配置所有路由,而是在控制器级别进行配置。

让我们看一个基于属性路由的示例。

首先,让我们删除之前在startup.cs类文件中的Configure方法中创建的基于约定的路由:

public void Configure(IApplicationBuilder app) 
    { 
        app.UseIISPlatformHandler(); 
        app.UseMvc(); 
        //app.UseMvc(routes => 
        //{ 
        //    routes.MapRoute(name: "FirstRoute",
        //                    template: "Hello", 
        //                    defaults: new { controller = "Home",  
        //                    action = "Index2" }); 

        //    routes.MapRoute(name: "default",
        //                 template:"
        //                {controller=Employee}/{action=Index}/{id?}"); 
        //}); 
    } 

然后,我们可以在控制器本身配置路由。 在下面的代码中,我们为之前创建的home控制器添加了路由配置:

namespace Validation.Controllers 
{ 
    public class HomeController : Controller 
    { 
        // GET: /<controller>/ 
        [Route("Home")] 
        public IActionResult Index() 
        { 
            return Content("Index action method"); 
        } 
        [Route("Home/Index3")] 
        public IActionResult Index2() 
        { 
            return Content("Index2 action method"); 
        } 
    } 
} 

我们在控制器的action方法中使用了Route属性。 在Route属性中传递的值将充当 URL 模式。 例如,当我们访问 URLhttp://localhost:49831/Home/时,将调用HomeControllerIndex方法。 当我们访问 URLhttp://localhost:49831/Home/Index3时,将调用HomeControllerIndex2方法。 请注意,URL 模式和action方法名不需要匹配。 在前面的示例中,我们调用了Index2操作方法,但 URL 模式使用了Index3http://localhost:49831/Home/Index3

同时使用基于属性的路由和基于约定的路由时,优先使用基于属性的路由。

控制器级别的路由属性

您将注意到,对于action方法IndexIndex2的 URL 模式,我们在HomeHome/Index3两个 URL 模式中重复了控制器名称Home。 我们可以在controller级别定义它,而不是在action方法级别重复controller方法名称(或 URL 中的任何公共部分)。

在下面的代码中,URL 的公共部分(Home)在controller级别上定义,惟一部分在action方法级别上定义。 当 URL 模式被映射到控制器的action方法时,两个路由部分(在controller级别和action方法级别)被合并和匹配。 所以前面定义的路线和后面的路线没有区别。

如果你想在基于属性的路由中使用两个参数,你可以在花括号中传递它们。 在下面的例子中,我们对SayHello操作方法进行了这样的操作。

例如,URL 模式http://localhost:49831/Home/Index3仍然会映射到HomecontrollerIndex2方法:

namespace Validation.Controllers 
{     
    [Route("Home")] 
    public class HomeController : Controller 
    { 
        // GET: /<controller>/ 
        [Route("")] 
        public IActionResult Index() 
        { 
            return Content("Index action method"); 
        } 

        [Route("Index3")] 
        public IActionResult Index2() 
        { 
            return Content("Index2 action method"); 
        } 

 [Route("SayHello/{id}")] 
        public IActionResult SayHello(int id) 
        { 
            return Content("Say Hello action method"+id); 
        } 
    } 
} 

在控制器中以 HTTP 动作动词传递路由值

我们甚至可以通过 HTTP 动作动词(如HTTPGetHTTPPost)传递路由值,而不是通过Route属性传递路由值。

在下面的代码中,我们使用了HTTPGet属性来传递路由值。 对于Index方法,我们没有传递任何值,因此没有将路由值附加到controller方法级别定义的路由值上。 对于Index2方法,我们传递了Index3值,并且Index3将被附加到controller级别定义的路由值。 请注意,只有带有GET方法的 url 才会映射到action方法。 如果您使用POST方法访问相同的 URL 模式,这些路由将不会得到匹配,因此这些action方法将不会被调用。

namespace Validation.Controllers 
{     
    [Route("Home")] 
    public class HomeController : Controller 
    { 
        // GET: /<controller>/ 
        [HttpGet()] 
        public IActionResult Index() 
        { 
            return Content("Index action method"); 
        } 

        [HttpGet("Index3")] 
        public IActionResult Index2() 
        { 
            return Content("Index2 action method"); 
        } 
    } 
} 

路由约束

路由约束使您能够约束传递给控制器操作的值的类型。 例如,如果希望限制传递给int类型int的值,可以这样做。 下面就是这样一个例子:

[HttpGet("details/{id:int?}")] 
    public IActionResult Details(int id) 
    { 
      return View(); 
    } 

ASP。 净 5 (ASP.NET Core)甚至支持默认参数值,以便您可以传递默认参数:

[HttpGet("details/{id:int = 123}")] 
    public IActionResult Details(int id) 
    { 
      return View(); 
    } 

总结

在本章中,我们学习了路由及其工作原理。 我们了解了各种可用的路由。 我们通过不同的例子讨论了基于约定的路由和基于属性的路由。 我们还讨论了路由约束和可以传递的默认参数值。

在下一章中,我们将看到如何使应用看起来更好。