在ASP.NET MVC架構中,控制器在3大核心構件中處於中心地位,經過控制器支配模型和視圖,然而從瀏覽器發出的請求到控制器還須要路由的協助,路由將特定的請求和控制器的動做對應起來。web
在ASP.NET MVC程序中,路由主要有兩方面的職責:正則表達式
先看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路由集合中。app
解釋說明:框架
啓動程序,這時URL地址是:http://localhost:49730asp.net
其實該地址至關於在瀏覽器裏面輸入:http://localhost:49730/Home/Index,這時由於在路由規則裏面設置了默認值,若是沒有控制器和action方法,則默認是Home控制器下面的Index方法。網站
修改URL裏面的controller和action,代碼以下:ui
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。
看下面的截圖:
解釋說明:
看下面的示例:
首先修改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 »</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 »</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 »</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 »</a></p> </div> </div>
一、使用{parameter}作模糊匹配其實就是默認路由規則:
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
運行程序查看結果:
二、使用字面量作精確匹配
路由規則以下代碼所示:
routes.MapRoute( name: "const", url: "admin/{controller}/{action}" );
運行程序,在瀏覽器裏面輸入:http://localhost:64957/admin/home/index,運行結果以下:
三、不容許連續的URL參數
路由規則以下:
routes.MapRoute( name: "blx", // 錯誤的URL // url: "{language}{country}/{controller}/{action}" url: "{language}-{country}/{controller}/{action}" );
運行程序,URL裏面輸入:http://localhost:64957/chinese-china/home/index,運行結果以下:
看下面截圖:
解釋說明:
看下面的路由規則:
routes.MapRoute( name: "RouteRule", url: "{controller}/{action}/{query-name}/{*plus}" );
運行程序,在URL裏面輸入:http://localhost:64957/home/index/123/wqer_1234,運行結果以下:
看下面截圖:
解釋說明:
路由規則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 } ); } } }
看下面的截圖:
解釋說明:
路由規則代碼以下:
// 參數默認值一 routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
看下面截圖:
解釋說明:
路由規則以下:
// 參數默認值二:默認值不提供的必須經過URL提供 routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { action = "Index", id = UrlParameter.Optional });
這時直接運行程序,由於沒有提供controller,因此程序會報錯:
而後在URL裏面輸入:http://localhost:55650/Home,就能夠正常訪問了:
解釋說明:
路由規則以下:
// 參數默認值三:只提供中間參數的默認值是不起做用的 routes.MapRoute( name: "Default2", url: "{controller}/{action}/{id}", defaults: new { action = "Index" } );
這時候須要在瀏覽器裏面輸入完整的URL才能訪問。
看下面截圖:
解釋說明:
規律:使用/把URL劃分紅若干個部分,若是各個部分包含了URL參數和字面量,那麼給這些URL參數提供默認值是不起做用的。如圖所示,給參數2和參數3是不起做用的!
路由規則以下:
// 參數默認值四:只提供中間參數的默認值是不起做用的 routes.MapRoute( name: "Default2", url: "{controller}-{action}", defaults: new { action = "Index" });
運行程序,若是瀏覽器裏面只輸入http://localhost:55650/home- 是報錯的:
這時須要輸入完整的URL地址:http://localhost:55650/home-index
假如咱們想對URL後面的數字進行限制,好比四位數字或者兩位數字,以下圖所示,該如何限制呢?
以下圖所示:
解釋說明:
路由規則以下:
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}"); // 一、使用正則表達式設置參數值的約束 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,效果以下:
由於設置了約束month是2位整數,這時將month改成1位整數,而後輸入:http://localhost:51244/Home/Index/1/2019/5/24,效果以下:
這時程序就報錯了,說明設置的正則約束起做用了。
以下圖所示:
解釋說明:
路由規則以下:
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}"); // 二、使用約束類來約束參數值 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}" } ); // 一、使用正則表達式設置參數值的約束 //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 ,效果以下:
以下圖所示:
解釋說明:
解釋說明:
咱們注意到RigisterRoutes方法中默認的第一句代碼是routes.IgnoreRoute方法,他的做用就是排除路由,好比上圖下面的URL不會在路由表中匹配的,而是直接被忽略掉!
先看下面的截圖:
解釋說明:
上面說的UrlRoutingModule在哪裏呢?看下面截圖:
從控制器中獲取URL中的值共有三種方式:
解釋說明:
RouteDate.Values[「id」]就是當前字典上的路由數據,經過訪問鍵名的方式獲得鍵值,好比URL模式匹配的字符串是id,這裏必須是id。
Action方法的參數和路由字典的參數是對應的,MVC框架在執行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(); } 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 »</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 »</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 »</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 »</a></p> </div> </div>
程序運行效果:
控制器代碼以下:
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(); } } }
運行效果:
這時會遇到一個問題,若是在URL裏面還有其餘參數呢?好比下面的狀況
這時候若是要獲取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(); } } }
運行效果:
由於RouteData.Values是一個字典集合,因此能夠遍歷RouteData.Values,這樣不管URL裏面有多少參數,均可以獲取到對應的value值。
控制器代碼:
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(); } } }
運行效果:
解釋說明:
1.由路由生成URL其實就是簡單的兩句代碼,第一步就是使用RouteCollection對象的GetVirtualPath方法,經過該方法能夠返回一個VirtualPahData對象,該類型表示有關路由和虛擬路徑的信息,包含了兩個重載的方法,區別是第二個方法能夠指定路由項的名稱,就是添加路由時,設置的路由鍵名,參數Values表達生成URL時設置的參數值,是一個字典類型。
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(); } } }
界面運行效果:
在看下面一種方式:
控制器代碼:
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(); } } }
運行效果: