mvc——URL路由_1_定义路由(映射url到动作方法)

Posted 天赋吉运科技

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mvc——URL路由_1_定义路由(映射url到动作方法)相关的知识,希望对你有一定的参考价值。

在使用mvc的过程中,我们经常用到的就是路由,今天我们来了解一下路由的一些东西。

新建一个项目
    创建控制器
    创建视图


URL模式
创建一条简单的路由
定义默认值
使用静态的URL片段
    1、带有前缀的url
    2、带有可变元素片段的url
        ps:路由定义的顺序

    3、创建url中的别名

  在我们进行路由的讲解之前,我们要做一些准备,新建一个项目。

新建一个项目

       


  用”Empty(空)”模板创建一个新的MVC应用程序,并称此项目“UrIsAndRoutes”。
 

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


创建控制器

  为了演示路由特性,对此示例应用程序添加一些简单的控制器,以此对URL进行解释以调用动作方法的方式,因此,所用的视图模型都是视图包中的一些字符串值,用它们来报告控制器和动作方法的名称。首先,创建一个Home控制器,并设置其内容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace urlAndRoutes.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            ViewBag.Controller = "Home";
            ViewBag.Action = "Index";
            return View("ActionName");
        }
    }
}

创建一个customer控制器,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace urlAndRoutes.Controllers
{
    public class CustomerController : Controller
    {
        // GET: Customer
        public ActionResult Index()
        {
            ViewBag.Controller = "Customer";
            ViewBag.Action = "Index";
            return View("ActionName");
        }
        public ActionResult List()
        {
            ViewBag.Controller = "Customer";
            ViewBag.Action = "List";
            return View("ActionName");
        }
    }
}

创建admin控制器,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace urlAndRoutes.Controllers
{
    public class AdminController : Controller
    {
        // GET: Admin
        public ActionResult Index()
        {
            ViewBag.Controller = "Admin";
            ViewBag.Action = "Index";
            return View("ActionName");
        }
    }
}

创建视图

  在这些控制器的所有动作方法中,小编指定的都是ActionName视图,这让小编只需定义一个视图,并将它用于整个示例应用程序。在Views文件夹中创建Shared文件夹,并添加一个新的名为ActionName.cshtml的视图,内容如下:


@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ActionName</title>
</head>
<body>
    <div>The Controller is :@ViewBag.Controller</div>
    <div>The action is :@ViewBag.Action</div>
</body>
</html>

此时启动下面,如下图:

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


URL模式

  路由系统用一组路由来实现它的功能。这些路由共同组成了应用程序的URL架构(Schema)或方案(Scheme),这种URL架构(或方案)是应用程序能够识别并能对之做出响应的一组URL。
  我们不需要手动输入应用程序中打算支持的各个URL,而是让每一条路由都包含一个URL模式(Pattern),用它与一个输入URL进行比较。如果该模式与这个URL匹配,那么它(URL模式)便被路由系统用来对这个URL进行处理。让我们先从上述示例应用程序的一个URL开始:http://localhost:11853/home/index

  

mvc(5)——URL路由_1_定义路由(映射url到动作方法)
mvc(5)——URL路由_1_定义路由(映射url到动作方法)

        

        URLs可以分成几个片段。除主机名和查询字符串之外,这些URL的组成部分都用“/”字符进行分割。在这个示例URL中有两个片段,第一个片段含有单词“home”,第二个片段含有单词“Index”。很显然,第一个片段与控制器有关,而第二个片段与动作有关。
  当然,需要以一种路由系统能够理解的方式来表示这种关系。以下是做这件事的一个URL模式:{controller}/{action}
  当处理一个输入请求时,路由系统的工作是将这个请求URL与一个模式进行匹配,然后从此URL为这个模式中定义的片段变量提取出相应的值。片段变量用花括号(“{”和“}”字符)表示。上述示例模式有两个片段变量,其名称分别为”controller”和”action”,因此,controller片段变量的值将是home,而action片段变量的值将是Index。
  所谓“与一个模式匹配”是指,一个MVC应用程序通常会有几条路由,而路由系统会把输入URL逐一与每条路由的URL模式相比较,直到能找到一条匹配的路由为止(意即,这条路由中的URL模式与这个输入URL匹配)。
  默认情况下,一个URL模式将匹配具有正确片段数的任何URL。例如,模式
{controIler}/{action}将匹配任何具有两个片段的URL,如下表:


  

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


  

  表中突出了URL模式的两个关键行为:


URL模式是保守的(Conservative),因而只匹配与模式具有相同片段数的URL你可以从表中的第四、第五个例子看到这种情况(片段数不同就是不匹配)。
URL模式是宽松的(Liberal)。如果一个URL正好具有正确的片段数,该模式就会用来为片段变量提取值,而不管这个值可能是什么。

  正如前面己经提到的,路由系统并不知道关于MVC应用程序的任何情况,因此,即使不存在从一个URL提取出来的值所对应的控制器或动作,URL模式也会进行匹配(这里的含义是,只要模式匹配,路由系统便会从URL中为片段变量提取值,至于应用程序中是否实际存在相应的控制器和动作,路由系统是不管的)。你可以从表中的第二个例子中看到这种情况的演示。这个例子的URL中调换了Admin和Index片段,因此,从这个URL提取的值也被调换了,尽管示例项目中没有Index控制器。
  了解了这些,我们开始正式定义路由啦!!!!!


创建一条简单的路由

一旦在头脑中有了URL模式,便可以用它来定义一条路由。路由是在RouteConfig.cs文件中进行定义的,该文件位于项目的App_Start文件夹中。内容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

  在RouteConfig.cs文件中定义的静态RegisterRoutes方法是通过Global.asax.cs文件进行调用的,当启动应用程序时,它建立了一些核心的MVC特性。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);   //RouteConfig·RegisterRoutes方法的
调用
        }
    }
}

  下面将介绍如何在RouteConfig.cs文件的RegisterRoutes方法中,使用URL模式来创建一条路由。(我们删除了原有的url模式)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            Route myRoute = new Route("{controller}/{action}",new MvcRouteHandler());
            routes.Add("myRoute",myRoute);
        }
    }
}

  该清单创建了一个新的Route,以URL模式作为一个构造器参数,并将其表示成一个字符串。
  另外,还为构造器传递了一个MvcRouteHandIer实例。不同的ASP.NET技术提供了不同的类来定制路由的行为,而这个类(指MvcRouteHandIer类)是用于ASP.NETMVC应用程序的类。一旦创建了这个路由,就可以用Add方法把它添加到RouteCoIIection对象,在其中传递给这条路由所起的名字和已经创建的这条路由。

  上面是注册路由的方法,下面是另外一种更加方便的方法:
  使用在RouteCollection类所定义的MapRoute方法。下面的代码介绍如何用这个方法来注册路由。它和前面的示例有同样的效果,但语法更简洁。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}");
        }
    }
}

  通过运行应用程序,可以看到对路由所做修改的效果。当浏览器试图导航到应用程序的根URL时,你将看到一个错误。

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


  但如果导航到一个与{controIler}/{action}模式匹配的URL,将会出现下图的结果:
 

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


  上面的配置文件中,简单路由并未告诉MVC框架,如何对根URL的请求进行响应,并且只支持简单的、非常具体的URL模式。在功能上,要比VisualStudio在创建MVC项目时,添加到RouteConfig.cs文件中的路由所具备的功能暂时后退了一步(因为此刻的路由还无法对根URL进行解析)。

定义默认值

  前面曾解释过,URL模式是保守的,它们只匹配指定片段数的URL。改变这种行为的一个办法是使用默认值。当URL不包含与一个片段匹配的值时,便使用默认值。设置方法如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}", new { Action = "Index" });
        }
    }
}

  默认值是作为匿名类型的属性来提供的。上面的代码中为action变量提供了一个Index的默认值。这条路由将匹配所有两片段的URL,就像它之前所做的那样。例如,如果请求http://mydomain.com/Home/Index,该路山将为controller提取Home值,为action提取Index值。但是现在,由于己为action片段提供了一个默认值,该路由也将匹配单片段URL。当处理单片段URL时,路由系统将从唯一的URL片段中提取controller的值,并对action变量使用默认值。于是,可以请求http://mydomain.com/Home,并调用Home控制器上的Index动作方法。
  可以更进一步,定义根本不含任何片段变量的URL,只依靠默认值来标识controller和action。下面的代码中告诉我们如何为应用程序映射根URL。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}", new { Controller="Home", Action = "Index" });
        }
    }
}

  上面的代码中已经为controller和action变量提供默认值,为了方便解释:这里己经创建了与0个、1个或2个片段的ULR匹配的路由,如下表所示:


 

mvc(5)——URL路由_1_定义路由(映射url到动作方法)


  在输入URL中接收的片段数越少,所依赖的默认值便越多,直到接收一个无片段而只使用默认值的URL。重新启动该示例应用程序,你可以看到默认值的效果一一此时,当浏览器请求应用程序的根URL时,将使用controller和action片段变量的默认值,这将导致MVC框架请求Home控制器上的Index动作方法,如图所示:

mvc(5)——URL路由_1_定义路由(映射url到动作方法)

使用静态的URL片段

1、带有前缀的url

  并不是一个URL模式中的所有片段都需要是可变的,也可以创建具有静态片段的模式。假设希望匹配以下这种URL,以支持带有Public前缀的URL:http://mydomain.com/Pub1ic/Home/Index,可以通过使用如下代码所示的模式来做这件事。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}", new { Controller="Home", Action = "Index" });

            routes.MapRoute("","Public/{controller}/{action}",new { Controller="Home",Action="Index"});
        }
    }

}

  这个新的URL模式将只匹配含有三个片段的URL,第一个必须是Public.其他两个片段可以含有任何值,并将被用于controller和action变量。如果省略后两个片段,那么将使用默认值。

2、带有可变元素片段的url

当然,还可以创建既有静态也有可变元素片段的URL模式,比如下面的代码中:

//我是代码片段11
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("","X{controller}/{action}");
            routes.MapRoute("MyRoute", "{controller}/{action}", new { Controller = "Home", Action = "Index" });
            routes.MapRoute("","Public/{controller}/{action}",new { Controller="Home",Action="Index"});
        }
    }
}

  这条路由中的模式匹配任意两片段URL,而第一个片段以字母”x”打头。用于controller的值取自第一个片段除”X”以外的部分,Action值取自第二个片段。如果你启动应用程序并导航到/XHome/Index,可以看到这条路由的效果,结果如图


ps:路由定义的顺序


    代码片段11中,定义了一条新路由,并把它放在RegisterRoutes方法中的所有其他路由之前。这么做是因为路由是以它们在RouteC011ection对象中出现的顺序被运用的。MapRoute方法会把一条路由添加到该集合的末尾,让路由以它们被定义的顺序来运用。
    路由系统试图根据最先被定义的路由模式来匹配一个输入URL,并且只有在不匹配时,才会继续对下一条路由进行处理。路由被依次尝试,直至找到匹配的一条,或这组路由被尝试完。其结果是,必须首先定义较具体的路由。在代码片段11中所添加的路由要比其后的路由更具体些。假设顛倒路由的顺序,如下所示:

            routes.MapRoute("MyRoute", "{controller}/{action}", new { Controller = "Home", Action = "Index" });           
            routes.MapRoute("","X{controller}/{action}");


  那么第一条路由匹配任何具有0、1、2片段的URL,它将是被使用的一条。更具体
  的路由现在是列表的第二条,它将是不可到达的。新路由(第二条)去掉URL的前导”x”但旧路由(第一条)却不会这么做,因此,像这样的一条URL:http://localhost:8789/XHome/Index将以名为”XHome”的控制器为目标,而这是不存在的,因此,会导致一个“494一未找到”错误被发送给用户。


3、创建url中的别名

  可以结合静态片段和默认值为特定的路由创建一个别名。如果你已经公开地发布了URL方案,并且它与你的用户形成了一种契约,那么,创建这种别名可能是有用的。如果在这种情况下(指己与用户形成契约)重构应用程序,则需要保留以前的URL格式。设想以前用的是一个Shop控制器,现在要由Home控制器来替代。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace urlAndRoutes
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("shopdemo","shop/{action}",new { Controller="Home"});

        }
    }
}

  添加的这条路由匹配第一个片段是”Shop”的任意两片段URL,action的值取自第二个URL片段。这个URL模式不含controller的可变片段,因而会使用所提供的默认值。这意味着对Shop控制器上一个动作的请求会被转换成对Home控制器的请求。
 


源码下载:https://download.csdn.net/download/aiming66/10599459

---------------------


编辑:十五期   贺天远



以上是关于mvc——URL路由_1_定义路由(映射url到动作方法)的主要内容,如果未能解决你的问题,请参考以下文章

5_自定义url路由转换器

asp.net core 系列 5 MVC框架路由(上)

PHP单一文件入口框架简析

Url.Action 未输出自定义映射控制器路由

Flask Web开发实战:1.2-Hello, Flask!

004_URL 路由 - 高级路由特性