天天看點

ASP.NET MVC教程五:ASP.NET MVC中的路由

一、概述

在ASP.NET MVC架構中,控制器在3大核心構件中處于中心地位,通過控制器支配模型和視圖,然而從浏覽器發出的請求到控制器還需要路由的協助,路由将特定的請求和控制器的動作對應起來。

在ASP.NET MVC程式中,路由主要有兩方面的職責:

  1. 與入站的請求相比對,将這些請求映射到控制器的動作中。
  2. 構造出站的URL,這些URL可以響應控制器的動作。

二、路由原理

1、注冊路由

先看Global.asax中的代碼:

網站啟動的時候執行Application_Start方法,通過RouteConfig.RegisterRoutes(RouteTable.Routes)這段代碼進行路由的注冊,在RegisterRoutes上面F12轉到定義,可以檢視該方法,其實就是App_Start檔案夾下面的RouteConfig類,該類定義如下:

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

namespace ASPNETMVCDemo
{
    /// <summary>
    /// RouteCollection 所有路由的集合
    /// </summary>
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // 表示忽略路由   隻要URL滿足這個正則規則,就不使用路由
            // .axd 是因為iis6給沒有字尾的請求加個asd,然後支援MVC的請求
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            // 預設路由規則
            // 裡面使用的是命名參數,順序可以改變
            routes.MapRoute(
                // 路由名稱   RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆寫
                name: "Default",
                // url的正則規則,去掉域名和端口後的位址進行比對
                url: "{controller}/{action}/{id}",
                // 預設值
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}      
注冊路由其實就是把路由規則添加到RouteCollection路由集合中。

解釋說明:

  1. RegisterRoutes方法是在應用程式啟動時(Application_Start)被調用執行的。
  2. RegisterRoutes方法的作用:注冊路由。它的參數是一個集合對象,這個集合對象就是用來儲存多項路由資料的。一項路由資料實際上就是某種形式的URL路徑和控制器及其Action的關系,根據這個關系,MVC才能執行到控制器。
  3. 那麼怎麼添加這種路由資料呢?即調用RegisterRoutes方法裡面的routes.MapRoute方法。該方法的第一個參數是路由的名稱,類似于Dictionary字典裡面的key。第二個參數表示的是URL或者是位址。第三個參數是一個匿名類型,表示該路由相關的預設資料,可以看作一個字典。
  4. 我們注意到第二個參數其實就是占位符表示的URL,這個占位符是用大括号和裡面的字元串表示的。可以看出裡面不是某種寫死的URL位址(這裡的controller代表所有的控制器,而不是某一個具體的控制器。同理,action也是代表所有的方法,而不是某一個具體的action方法),這樣就增加了靈活性,就是用“/”把URL分成三部分。還有我們注意到占位符表示的URL是沒有域名的,這個是允許的,這種比對是不考慮域名的。
  5. 在ASP.NET MVC中我們見得最多的是“{controller}/{action}/{id}”這種形式的URL,那麼controller和action這兩個單詞是否有特殊的用途呢,能不能改變這兩個單詞的寫法。答案是不能的。這時因為會把controller、action和id當做字典或集合的key值來存儲對應的URL片段,這樣架構在處理時,會讀取鍵名為controller的資料,比如Home,然後得到要執行的控制器是HomeController。同樣會從字典中讀取鍵名為action的資料,比如Index,然後得到要執行的Action方法是Index。如果這兩個單詞寫錯了,就執行不到相應的controller和action方法了。是以一定要記住寫成controller和action是一種約定,其他參數的定義就沒有這種要求了。但是action和controller的位置可以修改。

啟動程式,這時URL位址是:http://localhost:49730

其實該位址相當于在浏覽器裡面輸入:http://localhost:49730/Home/Index,這時因為在路由規則裡面設定了預設值,如果沒有控制器和action方法,則預設是Home控制器下面的Index方法。

修改URL裡面的controller和action,代碼如下:

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

namespace ASPNETMVCDemo
{
    /// <summary>
    /// RouteCollection 所有路由的集合
    /// </summary>
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // 表示忽略路由   隻要URL滿足這個正則規則,就不使用路由
            // .axd 是因為iis6給沒有字尾的請求加個asd,然後支援MVC的請求
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            // 預設路由規則
            // 裡面使用的是命名參數,順序可以改變
            routes.MapRoute(
                // 路由名稱   RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆寫
                name: "Default",
                // url的正則規則,去掉域名和端口後的位址進行比對
                url: "{controller1}/{action1}/{id}",
                // 預設值
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}      

 然後運作程式檢視結果:

這時程式運作出錯,是以說controller和action千萬不能寫錯。把controller和action改回正确的,然後颠倒controller和action的位置,代碼如下:

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

namespace ASPNETMVCDemo
{
    /// <summary>
    /// RouteCollection 所有路由的集合
    /// </summary>
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // 表示忽略路由   隻要URL滿足這個正則規則,就不使用路由
            // .axd 是因為iis6給沒有字尾的請求加個asd,然後支援MVC的請求
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            // 預設路由規則
            // 裡面使用的是命名參數,順序可以改變
            routes.MapRoute(
                // 路由名稱   RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆寫
                name: "Default",
                // url的正則規則,去掉域名和端口後的位址進行比對
                url: "{action}/{controller}/{id}",
                // 預設值
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}      

 在運作程式檢視結果:

這說明:controller和action的位置是可以颠倒的。這時如果想輸入完整的URL位址就行通路就應該輸入:http://localhost:49730/Index/Home。

2、路由比對

2.1、比對方式一

看下面的截圖:

  1. {parameter}:花括弧加任意長度的字元串表示模糊比對,字元串不能定義成controller和action。預設路由規則就是使用模糊比對,沒有指明具體是哪個控制器裡面的哪個action方法。
  2. 字面量即一個常數字元串,這個字元串可以在大括弧與大括弧之間,也可以在最前面或最後面。
  3. 兩個大括弧之間沒有任何的字面量是不可以的。

 看下面的示例:

首先修改Home控制器裡面的Index方法,修改後的代碼如下:

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

namespace ASPNETMVCRoute.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            string paras = "";
            // 周遊擷取參數值
            foreach(KeyValuePair<string,object> keyValue in RouteData.Values)
            {
                paras += string.Format($"{keyValue.Key}={keyValue.Value}  ");
            }
            // 通過ViewData向頁面傳值
            ViewData["msg"] = paras;
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      

 修改對應的視圖,在界面展示ViewData["msg"]的值:

@{
    ViewBag.Title = "Home Page";
}

    <div class="jumbotron">
        <h1>ASP.NET</h1>
        <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
        <p><a href="https://asp.net" class="btn btn-primary btn-lg">Learn more &raquo;</a></p>
        <!--展示ViewData["msg"]的值-->
        <p style="color:red;">@ViewData["msg"]</p>
    </div>

<div class="row">
    <div class="col-md-4">
        <h2>Getting started</h2>
        <p>
            ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
            enables a clean separation of concerns and gives you full control over markup
            for enjoyable, agile development.
        </p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301865">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Get more libraries</h2>
        <p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301866">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Web Hosting</h2>
        <p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a></p>
    </div>
</div>      

 1、使用{parameter}做模糊比對其實就是預設路由規則:

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

 運作程式檢視結果:

2、使用字面量做精确比對

路由規則如下代碼所示:

routes.MapRoute(
      name: "const",
      url: "admin/{controller}/{action}"
);      

 運作程式,在浏覽器裡面輸入:http://localhost:64957/admin/home/index,運作結果如下:

3、不允許連續的URL參數

路由規則如下:

routes.MapRoute(
      name: "blx",
      // 錯誤的URL
      // url: "{language}{country}/{controller}/{action}"
      url: "{language}-{country}/{controller}/{action}"
);      

運作程式,URL裡面輸入:http://localhost:64957/chinese-china/home/index,運作結果如下:

2.2、比對方式二

看下面截圖:

  1. 使用“*”來比對URL剩餘的部分,如*plus放在一個表達式的尾部,最後尾部的URL會儲存為plus為鍵名的字典值。

看下面的路由規則:

routes.MapRoute(
       name: "RouteRule",
       url: "{controller}/{action}/{query-name}/{*plus}"
);      

 運作程式,在URL裡面輸入:http://localhost:64957/home/index/123/wqer_1234,運作結果如下:

2.3、比對方式三

  1. 在URL表達式中有一種特殊的情況,就是URL表達式可能和實際的URL有多種比對情況,這時候遵守貪婪比對的原則(即從後往前進行比對)。

路由規則1:

routes.MapRoute(
     name: "tlppone",
     url: "{controller}/{action}/{filename}.{ext}"
);      

 運作程式,在URL裡面輸入:http://localhost:64957/home/index/2342.234.234.aspx,運作結果如下:

路由規則2:

routes.MapRoute(
     name: "tlpptwo",
     url: "{controller}/{action}/{foo}xyz{bar}"
);      

 運作程式,在URL裡面輸入:http://localhost:64957/home/index/xyzxyzxyzwer23,運作結果如下:

完整路由規則代碼如下:

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

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

            // 使用字面量做精确比對
            // http://localhost:64957/admin/home/index
            routes.MapRoute(
                name: "const",
                url: "admin/{controller}/{action}"
                );

            // 不允許連續的URL參數
            // http://localhost:64957/chinese-china/home/index
            routes.MapRoute(
                  name: "blx",
                  // 錯誤的URL
                  // url: "{language}{country}/{controller}/{action}"
                  url: "{language}-{country}/{controller}/{action}"
              );

            // 使用*号比對URL剩餘部分
            // http://localhost:64957/home/index/2342.234.234.aspx 與第一個和第二個路由規則都比對,顯示第一個,說明路由比對的順序是從上往下
            // http://localhost:64957/home/index/123/wqer_1234
            routes.MapRoute(
                name: "RouteRule",
                url: "{controller}/{action}/{query-name}/{*plus}"
            );


            // 貪婪比對
            // http://localhost:64957/home/index/2342.234.234.aspx
            routes.MapRoute(
               name: "tlppone",
               url: "{controller}/{action}/{filename}.{ext}"
            );

            // 貪婪比對2
            // http://localhost:64957/home/index/xyzxyzxyzwer23
            routes.MapRoute(
               name: "tlpptwo",
               url: "{controller}/{action}/{foo}xyz{bar}"
           );

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

3、URL參數預設值

3.1、參數預設值一

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 如上圖所示,我們使用了參數的預設值,上圖下方的URL都是比對這個路由的,如果沒有使用預設值,那麼就隻能使用http://localhost/home/index/1這種完整形式的URL位址了。

路由規則代碼如下:

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

3.2、參數預設值二

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 首先我們說的路由項隻提供部分URL片段預設值的情況,一條規則就是如果在路由項中使用預設值,但是沒有提供全部預設值,那麼沒有提供預設值的必須通過URL提供。在上面截圖中,控制器必須在URL裡面提供。
// 參數預設值二:預設值不提供的必須通過URL提供
routes.MapRoute(
       name: "Default",
       url: "{controller}/{action}/{id}",
       defaults: new { action = "Index", id = UrlParameter.Optional });      

 這時直接運作程式,因為沒有提供controller,是以程式會報錯:

ASP.NET MVC教程五:ASP.NET MVC中的路由

然後在URL裡面輸入:http://localhost:55650/Home,就可以正常通路了:

ASP.NET MVC教程五:ASP.NET MVC中的路由

3.4、參數預設值三

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 如果隻提供了部分參數,而且提供的部分參數是URL表達式中間的,如上圖所示,這種情況下action是不起作用的,是以,這種定義預設值的方式是沒有意義的!
// 參數預設值三:隻提供中間參數的預設值是不起作用的
routes.MapRoute(
     name: "Default2",
     url: "{controller}/{action}/{id}",
     defaults: new { action = "Index" }
);      

這時候需要在浏覽器裡面輸入完整的URL才能通路。

3.4、參數預設值四

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 最後一種預設值的特殊情況,就是在URL表達式中使用字面量,注意這個字面量是除-之外的任意字元的組合,那麼字面量相鄰的URL參數的預設值是不起作用的。
  2. 規律:使用/把URL劃分成若幹個部分,如果各個部分包含了URL參數和字面量,那麼給這些URL參數提供預設值是不起作用的。如圖所示,給參數2和參數3是不起作用的!
// 參數預設值四:隻提供中間參數的預設值是不起作用的
routes.MapRoute(
         name: "Default2",
         url: "{controller}-{action}",
         defaults: new { action = "Index" });      

運作程式,如果浏覽器裡面隻輸入http://localhost:55650/home- 是報錯的:

ASP.NET MVC教程五:ASP.NET MVC中的路由

這時需要輸入完整的URL位址:http://localhost:55650/home-index

ASP.NET MVC教程五:ASP.NET MVC中的路由

4、參數值限制

 假如我們想對URL後面的數字進行限制,比如四位數字或者兩位數字,如下圖所示,該如何限制呢?

ASP.NET MVC教程五:ASP.NET MVC中的路由

1、使用正規表達式

如下圖所示:

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 在MVC的路由中我們可以對URL的各個參數定義限制,有兩種限制方法,第一種是使用正規表達式,如上圖所示。
  2. MapRoute提供了一個重載方法,就是在預設值後面增加了一個限制的參數,這個參數可以使用匿名類型設定值,在匿名類裡面可以設定各種參數對應的正規表達式,如上圖所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

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

            // 1、使用正規表達式設定參數值的限制
            routes.MapRoute(
              name: "Default1",
              url: "{controller}/{action}/{id}/{year}/{month}/{day}",
              defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
              // year是4位整數 month和day是2位整數
              constraints:new { year = @"\d{4}",month=@"\d{2}",day=@"\d{2}"}
             );

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

 運作程式,在浏覽器裡面輸入:http://localhost:51244/Home/Index/1/2019/05/24,效果如下:

ASP.NET MVC教程五:ASP.NET MVC中的路由

因為設定了限制month是2位整數,這時将month改為1位整數,然後輸入:http://localhost:51244/Home/Index/1/2019/5/24,效果如下:

ASP.NET MVC教程五:ASP.NET MVC中的路由

這時程式就報錯了,說明設定的正則限制起作用了。

2、使用限制類

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 在有些時候,如果限制規則很複雜或者正規表達式很難寫,或者你根本就不擅長寫正規表達式,那麼可以考慮第二種限制方式:限制類。
  2. 如上圖所示:定義限制類就是要實作IRouteConstraint接口的Match方法,這個方法就是用來判斷接口是否比對的。使用這個限制類的方法也很簡單,就是在以前使用正規表達式的地方,換成用限制類的執行個體指派,如上圖所示。

 路由規則如下:

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

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

            // 2、使用限制類來限制參數值
            routes.MapRoute(
               name: "Default1",
               url: "{controller}/{action}/{id}/{year}/{month}/{day}",
               defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
               // 使用限制類的執行個體
               constraints: new { year = @"\d{4}", month =new MonthConstraint(), day = @"\d{2}" }
              );

            // 1、使用正規表達式設定參數值的限制
            //routes.MapRoute(
            //  name: "Default1",
            //  url: "{controller}/{action}/{id}/{year}/{month}/{day}",
            //  defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            //  // year是4位整數 month和day是2位整數
            //  constraints:new { year = @"\d{4}",month=@"\d{2}",day=@"\d{2}"}
            // );

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

    /// <summary>
    /// 對月進行限制,實作IRouteConstraint接口
    /// 對年或者日進行限制同理
    /// </summary>
    public class MonthConstraint : IRouteConstraint
    {
        // 實作Match方法
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            //  values["month"]表示根據鍵名或者值
            //  長度為2,并且在1到12之間表示比對通過傳回true,否則不通過傳回false
            if (values["month"].ToString().Length==2 &&
                Convert.ToInt32(values["month"])>=1 &&
                Convert.ToInt32(values["month"]) <=12)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}      

 運作程式,在浏覽器裡面輸入:http://localhost:51244/Home/Index/2/2019/05/24 ,效果如下:

ASP.NET MVC教程五:ASP.NET MVC中的路由

5、路由比對順序

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 如圖所示,上面的URL跟哪個路由規則比對呢?答案是比對Default1這個路由,為什麼會是這樣呢?其實如果隻注冊單獨的一條路由,這兩條路由規則都是比對這個URL的,這裡有一個原則:如果有多條路由都和這個URL比對,那麼就是排在最前面的優先比對,排在後面的就不在進行比對。

6、排除路由

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 我們注意到RigisterRoutes方法中預設的第一句代碼是routes.IgnoreRoute方法,他的作用就是排除路由,比如上圖下面的URL不會在路由表中比對的,而是直接被忽略掉!
  2. 如果出了.axd以外的檔案需要忽略,那麼在IgnoreRoute方法裡面添加需要忽略的路由即可。

5、由URL到控制器

先看下面的截圖:

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 通過前面路由注冊的代碼會最終形成一個路由集合的資料,可以看作是一個路由表(RouteTable),那麼請求是如何通過URL進入到相應的控制器及Action方法的呢?
  2. 如上圖所示,請求到達ASP.NET MVC應用程式後,首先會經過一個名為“UrlRoutingModule”的HttpModule,HttpModule可以過濾每一個請求,UrlRoutingModule的作用就是根據請求的URL從路由表中查找和URL比對的路由,然後從比對的路由中得到一個名為MvcHandler的HttpHandler,之後就執行它的ProcessRequest方法,在ProcessRequest方法的内部找到Controller,并繼續往下執行。
  3. 說到這裡可能有疑問:某項路由資料是怎樣聯系到一個HttpHandler的呢?如下圖中的源碼所示:MapRoute方法實際上包含這樣一段代碼,在new的時候會初始化一個MvcRouteHandler對象,然後通過MvcRouteHandler的GetHttpHandler方法可以得到真正的處理程式MvcHandler。
ASP.NET MVC教程五:ASP.NET MVC中的路由

上面說的UrlRoutingModule在哪裡呢?看下面截圖:

ASP.NET MVC教程五:ASP.NET MVC中的路由

6、從控制器中擷取URL值的方式

從控制器中擷取URL中的值共有三種方式:

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. Request.QueryString隻能擷取以?分隔的參數值!
  2. RouteDate.Values[“id”]就是目前字典上的路由資料,通過通路鍵名的方式得到鍵值,比如URL模式比對的字元串是id,這裡必須是id。
  3. Action方法的參數和路由字典的參數是對應的,MVC架構在執行action之前會首先為這些參數指派。

6.1、Request.QueryString

控制器代碼如下:

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

namespace MVCURlValue.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        ///  Request.QueryString
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            if(Request.QueryString["bookid"]!=null)
            {
                string value = Request.QueryString["bookid"];
                ViewData["msg"] = value;
            }

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      

視圖也代碼如下:

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="https://asp.net" class="btn btn-primary btn-lg">Learn more &raquo;</a></p>
    <p style="color:red;font-weight:bold;">@ViewData["msg"]</p>
</div>

<div class="row">
    <div class="col-md-4">
        <h2>Getting started</h2>
        <p>
            ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
            enables a clean separation of concerns and gives you full control over markup
            for enjoyable, agile development.
        </p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301865">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Get more libraries</h2>
        <p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301866">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Web Hosting</h2>
        <p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a></p>
    </div>
</div>      

程式運作效果:

ASP.NET MVC教程五:ASP.NET MVC中的路由

6.2、RouteData.Values

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

namespace MVCURlValue.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        ///  Request.QueryString
        /// </summary>
        /// <returns></returns>
        //public ActionResult Index()
        //{
        //    if(Request.QueryString["bookid"]!=null)
        //    {
        //        string value = Request.QueryString["bookid"];
        //        ViewData["msg"] = value;
        //    }

        //    return View();
        //}


        /// <summary>
        ///  RouteData.Values
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            string value = $"controller={RouteData.Values["controller"]},action={RouteData.Values["action"]}";
            ViewData["msg"] = value;

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      

運作效果:

ASP.NET MVC教程五:ASP.NET MVC中的路由

這時會遇到一個問題,如果在URL裡面還有其他參數呢?比如下面的情況

ASP.NET MVC教程五:ASP.NET MVC中的路由

這時候如果要擷取id的值就要修改代碼,那麼有沒有其他簡便的方式呢?看下面代碼:

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

namespace MVCURlValue.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        ///  Request.QueryString
        /// </summary>
        /// <returns></returns>
        //public ActionResult Index()
        //{
        //    if(Request.QueryString["bookid"]!=null)
        //    {
        //        string value = Request.QueryString["bookid"];
        //        ViewData["msg"] = value;
        //    }

        //    return View();
        //}


        /// <summary>
        ///  RouteData.Values
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            // 方式一
            //string value = $"controller={RouteData.Values["controller"]},action={RouteData.Values["action"]}";

            // 方式二
            string value = "";
            foreach(var item in RouteData.Values)
            {
                value += $"{item.Key}={item.Value}  ";
            }

            ViewData["msg"] = value;

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      

 運作效果:

ASP.NET MVC教程五:ASP.NET MVC中的路由

因為RouteData.Values是一個字典集合,是以可以周遊RouteData.Values,這樣無論URL裡面有多少參數,都可以擷取到對應的value值。

6.3、action參數

控制器代碼:

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

namespace MVCURlValue.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        ///  Request.QueryString
        /// </summary>
        /// <returns></returns>
        //public ActionResult Index()
        //{
        //    if(Request.QueryString["bookid"]!=null)
        //    {
        //        string value = Request.QueryString["bookid"];
        //        ViewData["msg"] = value;
        //    }

        //    return View();
        //}


        /// <summary>
        ///  RouteData.Values
        /// </summary>
        /// <returns></returns>
        //public ActionResult Index()
        //{
        //    // 方式一
        //    //string value = $"controller={RouteData.Values["controller"]},action={RouteData.Values["action"]}";

        //    // 方式二
        //    string value = "";
        //    foreach(var item in RouteData.Values)
        //    {
        //        value += $"{item.Key}={item.Value}  ";
        //    }

        //    ViewData["msg"] = value;

        //    return View();
        //}



        /// <summary>
        ///  action參數
        ///  方法參數名稱必須和URL裡面參數名稱保持一緻
        /// </summary>
        /// <returns></returns>
        public ActionResult Index(string controller,string action)
        {
            string value = $"controller={controller},action={action}";
            ViewData["msg"] = value;

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      
ASP.NET MVC教程五:ASP.NET MVC中的路由

7、由路由到URL

ASP.NET MVC教程五:ASP.NET MVC中的路由
  1. 1.由路由生成URL其實就是簡單的兩句代碼,第一步就是使用RouteCollection對象的GetVirtualPath方法,通過該方法可以傳回一個VirtualPahData對象,該類型表示有關路由和虛拟路徑的資訊,包含了兩個重載的方法,差別是第二個方法可以指定路由項的名稱,就是添加路由時,設定的路由鍵名,參數Values表達生成URL時設定的參數值,是一個字典類型。
  2. 1.得到VirtualPahData執行個體後,就可以通過他的VirtualPath屬性值得到URL位址,它是一個字元串類型,從路由的這個功能可以看出,他是有雙向功能的,不同于URL重寫!

看下面的案例:

修改RouteConfig代碼如下:

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

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

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

            // 預設路由比對規則
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}      
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MVCRouteToUrl.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // 1.不使用路由名稱的方式生成URL
            VirtualPathData vp= RouteTable.Routes.GetVirtualPath(null, new RouteValueDictionary(new { controller = "Home", action = "Index2", id = 4 }));
            string url = vp.VirtualPath;
            ViewData["msg"] = url;

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      

 界面運作效果:

ASP.NET MVC教程五:ASP.NET MVC中的路由

在看下面一種方式:

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

namespace MVCRouteToUrl.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // 1.不使用路由名稱的方式生成URL
            //VirtualPathData vp= RouteTable.Routes.GetVirtualPath(null, new RouteValueDictionary(new { controller = "Home", action = "Index2", id = 4 }));
            //string url = vp.VirtualPath;
            //ViewData["msg"] = url;
            // 2.根據路由名稱生成URL
            // 因為controller和id有預設值,是以這裡隻指定action的值
            VirtualPathData vp = RouteTable.Routes.GetVirtualPath(null, "Default2", new RouteValueDictionary(new { action = "Index5" }));
            string url = vp.VirtualPath;
            ViewData["msg"] = url;

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}      
ASP.NET MVC教程五:ASP.NET MVC中的路由