zoukankan      html  css  js  c++  java
  • ASP.NET MVC Route详解

    Routing深入详解

      首先,ASP.Net MVC项目是URL请求驱动的,为什么访问localhost/home/index会传递给HomeController中名为index的action(即HomeController类中的index方法)?

    下面,我们一一来看下。

    1.1 Routing的作用

      假如有一个请求:localhost/home/index,那么路由需要做的事情如下:

      (1)确定Controller

        (2)确定Action

      (3)确定其他参数

      (4)根据识别出来的数据,将请求传递给Controller和Action

    1.2 神奇的路由规则

      根据路由的作用,我们可以知道它是一个“指路人”,指示我们的请求应该到达哪个Controller中的Action。那么,它是根据什么规则来指路的呢?我们可以在App_Start文件夹中的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 }
          );
    }
    复制代码

      (1)首先,第一句routes.IgnoreRoute代表对所有axd的资源访问请求进行忽略,直接进行URL访问;这里可以阅读参考资料第(5)篇,了解其详细含义,这里就不再赘述;

      (2)然后,第二句开始使用MapRoute方法对整个网站定义了一个路由识别规则,这个规则的name是Default,url规则为:{controller}/{action}/{id}。例如我们要访问的URL为:localhost/home/index,在这个URL中,localhost是域名, 所以首先要去掉域名部分: home/index,也是就对应了上面代码中的这种URL结构: {controller}/{action}/{id}。正是因为我们建立了这种URL结构的识别规则,,所以能够识别出 Controller是home, action是index, id没有则为默认值""。

      (3)在MapRoute方法中为所有URL请求定义了一个defaults默认值:controller为空则指向Home,action为空则指向Index,而id则是可选的,非必须要的。

      这里,对于路由规则需要注意的有两点:

      (1)可以有多条路由规则;

      (2)路由规则是有顺序的(前面的规则被匹配后,后面的规则就不再匹配);

      我们可以在RegisterRoutes这个方法中添加一条自定义路由规则,并取名为Default2,具体规则代码如下:

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

      这下如果我们以:localhost/Home-Index来访问时,我们原本想要的是根据Default2这个路由规则访问Home控制器下的Index这个Action,但却被告知以404提示:

      这是为什么呢?我们再来看看RegisterRoutes这个方法:

    复制代码
    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 }
                );
    
                routes.MapRoute(
                    name: "Default2",
                    url: "{controller}-{action}-{id}",
                    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
    }
    复制代码

      我们刚刚提到,路由规则是有顺序的(前面的规则被匹配后,后面的规则就不再匹配)。那么,可以推断,由于Default2在Default之后,有可能我们的请求localhost/Home-Index已经被Default这个规则所匹配了,因此Default2规则根本没有出场Show一下。那么,在Default规则中,它将Home-Index作为Controller的名字匹配,去访问Home-Index这个Controller,而Action使用默认的Index,那么它所请求的应该是这个URL:/localhost/Home-Index/Index。由于网站中,并没有Home-Index这个Controller,所以也就出现了刚刚那个404页面。

    1.3 MapRoute方法介绍

      (1)MapRoute方法提供了以下几种方式的重载

      MapRoute( string name, string url);
      MapRoute( string name, string url, object defaults);
      MapRoute( string name, string url, string[] namespaces);
      MapRoute( string name, string url, object defaults, object constraints); MapRoute( string name, string url, object defaults, string[] namespaces);
      MapRoute( string name, string url, object defaults, object constraints, string[] namespaces);

      我们在上面所使用的便是第二种重载。

      (2)MapRoute方法参数详细介绍:

      ①name参数:

      规则名称, 可以随意起名。不可以重名,否则会发生错误: “路由集合中已经存在名为“Default”的路由。路由名必须是唯一的”。

      ②url参数:

      url获取数据的规则,这里不是正则表达式,将要识别的参数括起来即可,比如: {controller}/{action}

      最少只需要传递name和url参数就可以建立一条Routing(路由)规则,比如实例中的规则完全可以改为:

      routes.MapRoute( "Default", "{controller}/{action}");

      ③defaults参数:
      url参数的默认值:如果一个url只有controller: localhost/home/,而且我们只建立了一条url获取数据规则: {controller}/{action},那么这时就会为action参数设置defaults参数中规定的默认值。由于defaults参数是Object类型,所以可以传递一个匿名类型来初始化默认值:new { controller = "Home", action = "Index" }。
      在ASP.Net MVC网站默认实例中使用的是三个参数的MapRoute方法:
    routes.MapRoute(
         name: "Default",
         url: "{controller}/{action}/{id}",
         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
      ④constraints参数: 
      用来限定每个参数的规则或Http请求的类型。constraints属性是一个RouteValueDictionary对象,也就是一个字典表,但是这个字典表的值可以有两种类型:
      一是:用于定义正则表达式的字符串(正则表达式不区分大小写)。通过使用正则表达式可以规定参数格式,比如controller参数只能为4位数字:new { controller = @"d{4}"}
    复制代码
    routes.MapRoute(
         name: "Default2",
         url: "{controller}-{action}-{id}",
         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
         constraints: new { controller = @"d{4}" }
    );
    复制代码
     
      二是:一个用于实现 IRouteConstraint 接口且包含Match方法的对象。

      例如:通过第IRouteConstraint 接口可以限制请求的类型(是GET还是POST)。因为System.Web.Routing中提供了HttpMethodConstraint类,,这个类实现了IRouteConstraint 接口。

      我们可以通过为RouteValueDictionary字典对象添加键为"httpMethod", 值为一个HttpMethodConstraint对象来为路由规则添加HTTP 谓词的限制,比如限制一条路由规则只能处理GET请求:httpMethod = new HttpMethodConstraint( "GET" )

    复制代码
    routes.MapRoute(
         name: "Default2",
         url: "{controller}-{action}-{id}",
         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
         constraints: new { 
               controller = @"d{4}", 
               httpMethod = new HttpMethodConstraint("GET") }
    );
    复制代码

    1.4 URL路由实例详解

      一般来说,对于一个网站为了SEO友好,网址的URL层次最好不要超过三层:localhost/{频道}/{具体网页},其中域名第一层, 频道第二层, 那么最后的网页就只剩下最后一层了。如果使用默认实例中的“{controller}/{action}/{其他参数}"的形式则会影响网站的SEO。

      假设我们有一个综合型服务网站,其中有租房频道、酒店频道、KTV频道、电影院频道等等。我们应该怎样来设计URL路由规则呢?

      (1)首先,我们知道:可以有多条路由规则,但是路由规则是有顺序的(前面的规则被匹配后,后面的规则就不再匹配);所以,我们可以定义多条路由规则,粒度细的模块(比如:具体的酒店列表页面)路由规则放最前面,粒度粗的模块(比如:门户网站的首页)路由规则放在最后面。

      (2)其次,根据模块粒度划分层次结构,以粒度粗细排序为:网站首页->频道首页->具体内容;

      (3)最后,我们可以看一个具体的URL路由实例来分析一下:

    复制代码
    // 酒店列表页匹配
    routes.MapRoute(
         "酒店列表页",
         "hotels/{action}-{city}-{price}-{star}",
         new { controller = "Hotel", action = "list", city = "beijing", price = "-1,-1", star = "-1" },
         new { city = @"[a-zA-Z]*", price = @"(d)+\,(d)+", star = "[-1-5]" }
    );
    
    // 酒店频道所有匹配 
    routes.MapRoute(
         "酒店首页",
         "hotels/{*iiii}",
         new { controller = "Hotel", action = "default", hotelid = "" }
    );
                
    // 网站首页默认匹配
    routes.MapRoute(
         "网站首页",
         "{*values}",
         new { controller = "Home", action = "index" }
    );
    复制代码

      (4)我们可以分析一下上面的路由规则所实现的功能:

       ①访问 www.mywebsite.com/hotels/list-chengdu-100,200-3 会访问酒店频道的列表页,并传入查询参数(price为100,200,star为3);

       ②访问 www.mywebsite.com/hotels 下面的任何其他页面地址,都会跳转到酒店首页;

       ③访问 www.mywebsite.com 下面的任何地址,如果未匹配上面2条,则跳转到首页;

      (5)根据上面的规则和实现的功能,我们可以做一个简单的总结如下:

       ①Routing规则有顺序(按照添加是的顺序),如果一个url匹配了多个路由规则,则按照第一个匹配的路由规则执行

       ②由于上面的规则,要将具体频道的具体页面放在最上方,将频道首页 和 网站首页 放在最下方。

       ③{*values}表示后面可以使用任意的格式。

    1.5 URL路由调试

      在ASP.Net MVC中,默认是不允许对路由规则进行调试的。但是,我们可以通过使用RouteDebug来辅助进行调试。

      (1)首先,我们下载RouteDebug.dllMvcContrib.dll到我们的项目中,并添加对其的引用。

      (2)其次,在Global.asax中的Application_Start方法中添加一句代码:

      RouteDeug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); 

    复制代码
    protected void Application_Start()
    {
         AreaRegistration.RegisterAllAreas();
    
         WebApiConfig.Register(GlobalConfiguration.Configuration);
         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
         RouteConfig.RegisterRoutes(RouteTable.Routes);
         BundleConfig.RegisterBundles(BundleTable.Bundles);
         RouteDeug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
    }
    复制代码

      (3)最后,F5调试运行,我们请求localhost/Home-Index这个URL时,可以清楚地发现,系统将Home-Index匹配了第一条默认路由规则,也就是将Home-Index作为Controller的名称进行匹配,这也就证明了为什么我们输入这个请求不会匹配第二条Default2的路由规则出现刚刚那个404页面了。

  • 相关阅读:
    sed cat 命令
    Datetime 时间模块求日期差
    Selenium:截图显示等待
    SAS常用函数
    SAS笔记
    python 简明教程 【转】
    numpy 笔记
    android Adapter使用详解
    Eclipse的使用技巧之eclipse里的查找:
    Hierarchy Viewer之官方文档翻译之中英对照之未完不续版之使用详解.
  • 原文地址:https://www.cnblogs.com/Zhengxue/p/13064805.html
Copyright © 2011-2022 走看看