ASP.NET?MVC中的路由原理與用法
一、概述
在ASP.NET MVC架構(gòu)中,控制器在3大核心構(gòu)件中處于中心地位,通過控制器支配模型和視圖,然而從瀏覽器發(fā)出的請求到控制器還需要路由的協(xié)助,路由將特定的請求和控制器的動作對應(yīng)起來。
在ASP.NET MVC程序中,路由主要有兩方面的職責(zé):
- 與入站的請求相匹配,將這些請求映射到控制器的動作中。
- 構(gòu)造出站的URL,這些URL可以響應(yīng)控制器的動作。
二、路由原理
1、注冊路由
先看Global.asax中的代碼:
網(wǎng)站啟動的時候執(zhí)行Application_Start方法,通過RouteConfig.RegisterRoutes(RouteTable.Routes)這段代碼進(jìn)行路由的注冊,在RegisterRoutes上面F12轉(zhuǎn)到定義,可以查看該方法,其實就是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滿足這個正則規(guī)則,就不使用路由 // .axd 是因為iis6給沒有后綴的請求加個asd,然后支持MVC的請求 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // 默認(rèn)路由規(guī)則 // 里面使用的是命名參數(shù),順序可以改變 routes.MapRoute( // 路由名稱 RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆蓋 name: "Default", // url的正則規(guī)則,去掉域名和端口后的地址進(jìn)行匹配 url: "{controller}/{action}/{id}", // 默認(rèn)值 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
注冊路由其實就是把路由規(guī)則添加到RouteCollection路由集合中。
解釋說明:
- RegisterRoutes方法是在應(yīng)用程序啟動時(Application_Start)被調(diào)用執(zhí)行的。
- RegisterRoutes方法的作用:注冊路由。它的參數(shù)是一個集合對象,這個集合對象就是用來保存多項路由數(shù)據(jù)的。一項路由數(shù)據(jù)實際上就是某種形式的URL路徑和控制器及其Action的關(guān)系,根據(jù)這個關(guān)系,MVC才能執(zhí)行到控制器。
- 那么怎么添加這種路由數(shù)據(jù)呢?即調(diào)用RegisterRoutes方法里面的routes.MapRoute方法。該方法的第一個參數(shù)是路由的名稱,類似于Dictionary字典里面的key。第二個參數(shù)表示的是URL或者是地址。第三個參數(shù)是一個匿名類型,表示該路由相關(guān)的默認(rèn)數(shù)據(jù),可以看作一個字典。
- 我們注意到第二個參數(shù)其實就是占位符表示的URL,這個占位符是用大括號和里面的字符串表示的。可以看出里面不是某種硬編碼的URL地址(這里的controller代表所有的控制器,而不是某一個具體的控制器。同理,action也是代表所有的方法,而不是某一個具體的action方法),這樣就增加了靈活性,就是用“/”把URL分成三部分。還有我們注意到占位符表示的URL是沒有域名的,這個是允許的,這種匹配是不考慮域名的。
- 在ASP.NET MVC中我們見得最多的是“{controller}/{action}/{id}”這種形式的URL,那么controller和action這兩個單詞是否有特殊的用途呢,能不能改變這兩個單詞的寫法。答案是不能的。這時因為會把controller、action和id當(dāng)做字典或集合的key值來存儲對應(yīng)的URL片段,這樣框架在處理時,會讀取鍵名為controller的數(shù)據(jù),比如Home,然后得到要執(zhí)行的控制器是HomeController。同樣會從字典中讀取鍵名為action的數(shù)據(jù),比如Index,然后得到要執(zhí)行的Action方法是Index。如果這兩個單詞寫錯了,就執(zhí)行不到相應(yīng)的controller和action方法了。所以一定要記住寫成controller和action是一種約定,其他參數(shù)的定義就沒有這種要求了。但是action和controller的位置可以修改。
啟動程序,這時URL地址是:http://localhost:49730
其實該地址相當(dāng)于在瀏覽器里面輸入:http://localhost:49730/Home/Index,這時因為在路由規(guī)則里面設(shè)置了默認(rèn)值,如果沒有控制器和action方法,則默認(rèn)是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滿足這個正則規(guī)則,就不使用路由 // .axd 是因為iis6給沒有后綴的請求加個asd,然后支持MVC的請求 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // 默認(rèn)路由規(guī)則 // 里面使用的是命名參數(shù),順序可以改變 routes.MapRoute( // 路由名稱 RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆蓋 name: "Default", // url的正則規(guī)則,去掉域名和端口后的地址進(jìn)行匹配 url: "{controller1}/{action1}/{id}", // 默認(rèn)值 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
然后運行程序查看結(jié)果:
這時程序運行出錯,所以說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滿足這個正則規(guī)則,就不使用路由 // .axd 是因為iis6給沒有后綴的請求加個asd,然后支持MVC的請求 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // 默認(rèn)路由規(guī)則 // 里面使用的是命名參數(shù),順序可以改變 routes.MapRoute( // 路由名稱 RouteCollection是個字典 每個路由都要有自己的名稱,相同名稱的路由會被覆蓋 name: "Default", // url的正則規(guī)則,去掉域名和端口后的地址進(jìn)行匹配 url: "{action}/{controller}/{id}", // 默認(rèn)值 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
在運行程序查看結(jié)果:
這說明:controller和action的位置是可以顛倒的。這時如果想輸入完整的URL地址就行訪問就應(yīng)該輸入:http://localhost:49730/Index/Home。
2、路由匹配
2.1、匹配方式一
看下面的截圖:
解釋說明:
- {parameter}:花括弧加任意長度的字符串表示模糊匹配,字符串不能定義成controller和action。默認(rèn)路由規(guī)則就是使用模糊匹配,沒有指明具體是哪個控制器里面的哪個action方法。
- 字面量即一個常數(shù)字符串,這個字符串可以在大括弧與大括弧之間,也可以在最前面或最后面。
- 兩個大括弧之間沒有任何的字面量是不可以的。
看下面的示例:
首先修改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 = ""; // 遍歷獲取參數(shù)值 foreach(KeyValuePair<string,object> keyValue in RouteData.Values) { paras += string.Format($"{keyValue.Key}={keyValue.Value} "); } // 通過ViewData向頁面?zhèn)髦? 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(); } } }
修改對應(yīng)的視圖,在界面展示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 rel="external nofollow" rel="external nofollow" 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" rel="external nofollow" rel="external nofollow" >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" rel="external nofollow" rel="external nofollow" >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" rel="external nofollow" rel="external nofollow" >Learn more ?</a></p> </div> </div>
1、使用{parameter}做模糊匹配其實就是默認(rèn)路由規(guī)則:
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
運行程序查看結(jié)果:
2、使用字面量做精確匹配
路由規(guī)則如下代碼所示:
routes.MapRoute( name: "const", url: "admin/{controller}/{action}" );
運行程序,在瀏覽器里面輸入:http://localhost:64957/admin/home/index,運行結(jié)果如下:
3、不允許連續(xù)的URL參數(shù)
路由規(guī)則如下:
routes.MapRoute( name: "blx", // 錯誤的URL // url: "{language}{country}/{controller}/{action}" url: "{language}-{country}/{controller}/{action}" );
運行程序,URL里面輸入:http://localhost:64957/chinese-china/home/index,運行結(jié)果如下:
2.2、匹配方式二
看下面截圖:
解釋說明:
- 使用“*”來匹配URL剩余的部分,如*plus放在一個表達(dá)式的尾部,最后尾部的URL會保存為plus為鍵名的字典值。
看下面的路由規(guī)則:
routes.MapRoute( name: "RouteRule", url: "{controller}/{action}/{query-name}/{*plus}" );
運行程序,在URL里面輸入:http://localhost:64957/home/index/123/wqer_1234,運行結(jié)果如下:
2.3、匹配方式三
看下面截圖:
解釋說明:
- 在URL表達(dá)式中有一種特殊的情況,就是URL表達(dá)式可能和實際的URL有多種匹配情況,這時候遵守貪婪匹配的原則(即從后往前進(jìn)行匹配)。
路由規(guī)則1:
routes.MapRoute( name: "tlppone", url: "{controller}/{action}/{filename}.{ext}" );
運行程序,在URL里面輸入:http://localhost:64957/home/index/2342.234.234.aspx,運行結(jié)果如下:
路由規(guī)則2:
routes.MapRoute( name: "tlpptwo", url: "{controller}/{action}/{foo}xyz{bar}" );
運行程序,在URL里面輸入:http://localhost:64957/home/index/xyzxyzxyzwer23,運行結(jié)果如下:
完整路由規(guī)則代碼如下:
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}" ); // 不允許連續(xù)的URL參數(shù) // 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 與第一個和第二個路由規(guī)則都匹配,顯示第一個,說明路由匹配的順序是從上往下 // 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參數(shù)默認(rèn)值
3.1、參數(shù)默認(rèn)值一
看下面的截圖:
解釋說明:
- 如上圖所示,我們使用了參數(shù)的默認(rèn)值,上圖下方的URL都是匹配這個路由的,如果沒有使用默認(rèn)值,那么就只能使用http://localhost/home/index/1這種完整形式的URL地址了。
路由規(guī)則代碼如下:
// 參數(shù)默認(rèn)值一 routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
3.2、參數(shù)默認(rèn)值二
看下面截圖:
解釋說明:
- 首先我們說的路由項只提供部分URL片段默認(rèn)值的情況,一條規(guī)則就是如果在路由項中使用默認(rèn)值,但是沒有提供全部默認(rèn)值,那么沒有提供默認(rèn)值的必須通過URL提供。在上面截圖中,控制器必須在URL里面提供。
路由規(guī)則如下:
// 參數(shù)默認(rèn)值二:默認(rèn)值不提供的必須通過URL提供 routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { action = "Index", id = UrlParameter.Optional });
這時直接運行程序,因為沒有提供controller,所以程序會報錯:
然后在URL里面輸入:http://localhost:55650/Home,就可以正常訪問了:
3.4、參數(shù)默認(rèn)值三
解釋說明:
- 如果只提供了部分參數(shù),而且提供的部分參數(shù)是URL表達(dá)式中間的,如上圖所示,這種情況下action是不起作用的,所以,這種定義默認(rèn)值的方式是沒有意義的!
路由規(guī)則如下:
// 參數(shù)默認(rèn)值三:只提供中間參數(shù)的默認(rèn)值是不起作用的 routes.MapRoute( name: "Default2", url: "{controller}/{action}/{id}", defaults: new { action = "Index" } );
這時候需要在瀏覽器里面輸入完整的URL才能訪問。
3.4、參數(shù)默認(rèn)值四
看下面截圖:
解釋說明:
- 最后一種默認(rèn)值的特殊情況,就是在URL表達(dá)式中使用字面量,注意這個字面量是除-之外的任意字符的組合,那么字面量相鄰的URL參數(shù)的默認(rèn)值是不起作用的。
- 規(guī)律:使用/把URL劃分成若干個部分,如果各個部分包含了URL參數(shù)和字面量,那么給這些URL參數(shù)提供默認(rèn)值是不起作用的。如圖所示,給參數(shù)2和參數(shù)3是不起作用的!
路由規(guī)則如下:
// 參數(shù)默認(rèn)值四:只提供中間參數(shù)的默認(rèn)值是不起作用的 routes.MapRoute( name: "Default2", url: "{controller}-{action}", defaults: new { action = "Index" });
運行程序,如果瀏覽器里面只輸入http://localhost:55650/home-是報錯的:
這時需要輸入完整的URL地址:http://localhost:55650/home-index
4、參數(shù)值約束
假如我們想對URL后面的數(shù)字進(jìn)行限制,比如四位數(shù)字或者兩位數(shù)字,如下圖所示,該如何限制呢?
1、使用正則表達(dá)式
如下圖所示:
解釋說明:
- 在MVC的路由中我們可以對URL的各個參數(shù)定義約束,有兩種約束方法,第一種是使用正則表達(dá)式,如上圖所示。
- MapRoute提供了一個重載方法,就是在默認(rèn)值后面增加了一個約束的參數(shù),這個參數(shù)可以使用匿名類型設(shè)置值,在匿名類里面可以設(shè)置各種參數(shù)對應(yīng)的正則表達(dá)式,如上圖所示。
路由規(guī)則如下:
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、使用正則表達(dá)式設(shè)置參數(shù)值的約束 routes.MapRoute( name: "Default1", url: "{controller}/{action}/{id}/{year}/{month}/{day}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // year是4位整數(shù) month和day是2位整數(shù) constraints:new { year = @"\d{4}",month=@"\d{2}",day=@"\d{2}"} ); // 默認(rèn)路由 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,效果如下:
因為設(shè)置了約束month是2位整數(shù),這時將month改為1位整數(shù),然后輸入:http://localhost:51244/Home/Index/1/2019/5/24,效果如下:
這時程序就報錯了,說明設(shè)置的正則約束起作用了。
2、使用約束類
如下圖所示:
解釋說明:
- 在有些時候,如果約束規(guī)則很復(fù)雜或者正則表達(dá)式很難寫,或者你根本就不擅長寫正則表達(dá)式,那么可以考慮第二種約束方式:約束類。
- 如上圖所示:定義約束類就是要實現(xiàn)IRouteConstraint接口的Match方法,這個方法就是用來判斷接口是否匹配的。使用這個約束類的方法也很簡單,就是在以前使用正則表達(dá)式的地方,換成用約束類的實例賦值,如上圖所示。
路由規(guī)則如下:
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、使用約束類來約束參數(shù)值 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、使用正則表達(dá)式設(shè)置參數(shù)值的約束 //routes.MapRoute( // name: "Default1", // url: "{controller}/{action}/{id}/{year}/{month}/{day}", // defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // // year是4位整數(shù) month和day是2位整數(shù) // constraints:new { year = @"\d{4}",month=@"\d{2}",day=@"\d{2}"} // ); // 默認(rèn)路由 routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } /// <summary> /// 對月進(jìn)行約束,實現(xiàn)IRouteConstraint接口 /// 對年或者日進(jìn)行約束同理 /// </summary> public class MonthConstraint : IRouteConstraint { // 實現(xiàn)Match方法 public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { // values["month"]表示根據(jù)鍵名或者值 // 長度為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,效果如下:
5、路由匹配順序
如下圖所示:
解釋說明:
- 如圖所示,上面的URL跟哪個路由規(guī)則匹配呢?答案是匹配Default1這個路由,為什么會是這樣呢?其實如果只注冊單獨的一條路由,這兩條路由規(guī)則都是匹配這個URL的,這里有一個原則:如果有多條路由都和這個URL匹配,那么就是排在最前面的優(yōu)先匹配,排在后面的就不在進(jìn)行匹配。
6、排除路由
解釋說明:
我們注意到RigisterRoutes方法中默認(rèn)的第一句代碼是routes.IgnoreRoute方法,他的作用就是排除路由,比如上圖下面的URL不會在路由表中匹配的,而是直接被忽略掉!
- 如果出了.axd以外的文件需要忽略,那么在IgnoreRoute方法里面添加需要忽略的路由即可。
7、由URL到控制器
先看下面的截圖:
解釋說明:
- 通過前面路由注冊的代碼會最終形成一個路由集合的數(shù)據(jù),可以看作是一個路由表(RouteTable),那么請求是如何通過URL進(jìn)入到相應(yīng)的控制器及Action方法的呢?
- 如上圖所示,請求到達(dá)ASP.NET MVC應(yīng)用程序后,首先會經(jīng)過一個名為“UrlRoutingModule”的HttpModule,HttpModule可以過濾每一個請求,UrlRoutingModule的作用就是根據(jù)請求的URL從路由表中查找和URL匹配的路由,然后從匹配的路由中得到一個名為MvcHandler的HttpHandler,之后就執(zhí)行它的ProcessRequest方法,在ProcessRequest方法的內(nèi)部找到Controller,并繼續(xù)往下執(zhí)行。
- 說到這里可能有疑問:某項路由數(shù)據(jù)是怎樣聯(lián)系到一個HttpHandler的呢?如下圖中的源碼所示:MapRoute方法實際上包含這樣一段代碼,在new的時候會初始化一個MvcRouteHandler對象,然后通過MvcRouteHandler的GetHttpHandler方法可以得到真正的處理程序MvcHandler。
上面說的UrlRoutingModule在哪里呢?看下面截圖:
8、從控制器中獲取URL值的方式
從控制器中獲取URL中的值共有三種方式:
解釋說明:
- Request.QueryString只能獲取以?分隔的參數(shù)值!
RouteDate.Values[“id”]就是當(dāng)前字典上的路由數(shù)據(jù),通過訪問鍵名的方式得到鍵值,比如URL模式匹配的字符串是id,這里必須是id。
Action方法的參數(shù)和路由字典的參數(shù)是對應(yīng)的,MVC框架在執(zhí)行action之前會首先為這些參數(shù)賦值。
8.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 rel="external nofollow" rel="external nofollow" 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" rel="external nofollow" rel="external nofollow" >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" rel="external nofollow" rel="external nofollow" >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" rel="external nofollow" rel="external nofollow" >Learn more ?</a></p> </div> </div>
程序運行效果:
8.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(); } } }
運行效果:
這時會遇到一個問題,如果在URL里面還有其他參數(shù)呢?比如下面的情況
這時候如果要獲取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里面有多少參數(shù),都可以獲取到對應(yīng)的value值。
8.3、action參數(shù)
控制器代碼:
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參數(shù) /// 方法參數(shù)名稱必須和URL里面參數(shù)名稱保持一致 /// </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(); } } }
運行效果:
9、由路由到URL
解釋說明:
由路由生成URL其實就是簡單的兩句代碼,第一步就是使用RouteCollection對象的GetVirtualPath方法,通過該方法可以返回一個VirtualPahData對象,該類型表示有關(guān)路由和虛擬路徑的信息,包含了兩個重載的方法,區(qū)別是第二個方法可以指定路由項的名稱,就是添加路由時,設(shè)置的路由鍵名,參數(shù)Values表達(dá)生成URL時設(shè)置的參數(shù)值,是一個字典類型。
得到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 } ); // 默認(rèn)路由匹配規(guī)則 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.根據(jù)路由名稱生成URL // 因為controller和id有默認(rèn)值,所以這里只指定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(); } } }
運行效果:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- ASP.NET?MVC實現(xiàn)區(qū)域路由
- ASP.NET Core MVC學(xué)習(xí)教程之路由(Routing)
- 詳解ASP.NET Core MVC 源碼學(xué)習(xí):Routing 路由
- ASP.NET Core中使用默認(rèn)MVC路由的配置
- ASP.NET Core MVC 配置全局路由前綴
- 解讀ASP.NET 5 & MVC6系列教程(11):Routing路由
- 為ASP.NET MVC及WebApi添加路由優(yōu)先級
- asp.net mvc路由篇 如何找到 IHttpHandler方法介紹
- ASP.NET MVC3關(guān)于生成純靜態(tài)后如何不再走路由直接訪問靜態(tài)頁面
相關(guān)文章
使用Topshelf組件構(gòu)建簡單的Windows服務(wù)
這篇文章主要為大家詳細(xì)介紹了使用Topshelf組件構(gòu)建簡單的Windows服務(wù),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03asp.net Repeater 數(shù)據(jù)綁定代碼
asp.net Repeater 數(shù)據(jù)綁定代碼2010-03-03Asp.net防重復(fù)提交機(jī)制實現(xiàn)方法
在Button或其他控件加上下面兩個屬性:UseSubmitBehavior="false"及OnClientClick設(shè)置控件為不可用即可,感興趣的朋友可以參考下哈2013-04-04.Net站點設(shè)置多個路由對應(yīng)同一個Action
這篇文章介紹了.Net站點設(shè)置多個路由對應(yīng)同一個Action的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07