上一主題下一主題
«123»Pages: 1/3     Go
關鍵字
主題 : ASP.NET MVC4 URL Routing 深入與使用URL最佳實踐
級別: VIP四級

UID: 230365
精華: 12
發帖: 314
威望: 3432 點
學點: 380 點
貢獻: 2 點
好評: 1 點
學幣: 0 個
注冊時間: 2010-04-16
最后登錄: 2014-09-25
樓主  發表于: 2014-07-16 16:38||

0 ASP.NET MVC4 URL Routing 深入與使用URL最佳實踐

管理提醒: 本帖被 zylzyl 設置為精華(2014-07-17)
=`EVg>+^  
W@t{pXwLv  
?WBA:?=$58  
ekPn`U  
ASP.NET MV**** URL Routing 深入與使用URL最佳實踐 W61nJ7@  
g{e@I;F  
S{S。H?{F  
目錄: mQ=nU  
前言 {1}p+dEK  
URL Routing 的定義方式 oTb4T=  
示例準備 ]]6  
給片段變量定義默認值 *?R<gWCF  
定義靜態片段 BDcA_= ^R&  
自定義片段變量 {SwvUWOf"  
路由約束 115zvW  
定義請求磁盤文件路由 df8aM<&m3  
生成URL(鏈接) i{MzQE+_^  
URL方案最佳實踐 G|LcTV  
FQ BAt0  
內容: ]}9D*V  
1. 前言 3h4'DQ.g  
我們知道在ASP.NET Web Forms中,一個URL請求往往對應一個aspx頁面,一個aspx頁面就是一個物理文件,它包含對請求的****。 %-O[%Dy  
而在ASP.NET MVC中,一個URL請求是由對應的一個Controller中的Action來****的,由URL Routing來告訴MVC如何定位到正確的Controller和Action。 ZJ'FZ8Sx  
總的來說,URL Routing包含兩個主要功能:解析URL 和 生成URL,本文將圍繞這兩個大點進行講解。 mApl}I  
2. URL Routing 的定義方式 9._Osbp3P  
讓我們從下面這樣一個簡單的URL****始: K&;;{~md.  
;#n+$Q#:  
在域名的后面,默認使用“/”來對URL進行分段。路由系統通過類似于 {controller}/{action} 格式的字符串可以知道這個URL的 Admin 和 Index 兩個片段分別對應Controller和Action的名稱。 4^{~MgQWK+  
默認情況下,路由格式中用“/”分隔的段數是和URL域名的后面的段數是一致的,比如,對于{controller}/{action} 格式只會匹配兩個片段。如下表所示: (k<__W c_t  
X@^"@  
URL路由是在MVC工程中的App_Start文件夾下的RouteConfig.cs文件中的RegisterRoutes方法中定義的,下面是創建一個空MVC項目時系統生成的一個簡單URL路由定義: I7HP~v~  
public static void RegisterRoutes(RouteCollection routes) { Na>?1F"KHk  
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); h%!N!\  
    routes.MapRoute( [8rl{~9E  
        name: "Default", > m##JzWLr  
        url: "{controller}/{action}/{id}", L<O"36R  
        defaults: new { controller = "Home", action = "Index",  id = UrlParameter.Optional } b:YyzOqEu  
    ); w<G'gi]  
} vj+ S  
靜態方法RegisterRoutes是在Global.asax.cs文件中的Application_Start方法中被調用的,除了URL路由的定義外,還包含其他的一些MVC核心特性的定義: ;`}b .S =n  
protected void Application_Start() { hG qZB  
    AreaRegistration.RegisterAllAreas(); 8\9s,W:5  
    WebApiConfig.Register(GlobalConfiguration.Configuration); .>+jtp}  
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); }8?1)l  
    RouteConfig.RegisterRoutes(RouteTable.Routes); O>Ao#_*hOb  
    BundleConfig.RegisterBundles(BundleTable.Bundles); JB(P-Y#yyA  
} { , zg  
RouteConfig.RegisterRoutes方法中傳遞的是 RouteTable 類的靜態 Routes 屬性,返回一個RouteCollection的實例。其實,“原始”的定義路由的方法可以這樣寫: FX:'38-fk  
public static void RegisterRoutes(RouteCollection routes) { 93fClF|@  
ZY{zFg9  
    Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); $ZfoJR]%  
    routes.Add("MyRoute", myRoute); _do (   
} <O30X !QuK  
創建Route對象時用了一個URL格式字符串和一個MvcRouteHandler對象作為構造函數的參數。不同的ASP.NET技術有不同的RouteHandler,MVC用的是MvcRouteHandler。 -8D$[@y(  
這種寫法有點繁瑣,一種更簡單的定義方法是: zx=AT  
public static void RegisterRoutes(RouteCollection routes) { p'`pO"EO  
    routes.MapRoute("MyRoute", "{controller}/{action}"); ]Q*eCt;l"K  
} ~@N0$S  
這種方法簡潔易讀,一般我們都會用這種方法定義路由。 i}}}x  
3. 示例準備 `6 `oLu\l  
作為演示,我們先來準備一個Demo。創建一個標準的MVC應用程序,然后添加三個簡單的Controller,分別是HomeController、CustomerController和AdminController,代碼如下: .m \y6  
public class HomeController : Controller { ,?ci+M)  
             QP0[  
    public ActionResult Index() { b。sRB1  
        ViewBag.Controller = "Home"; 6<+8[o  
        ViewBag.Action = "Index"; $H2HVJ  
        return View("ActionName"); Q2 @Ugt$  
    } *d;D~"E<@  
} - |j4u#z  
public class CustomerController : Controller { #E#。`/4  
         u=9)A9  
    public ActionResult Index() { sCw X|  
        ViewBag.Controller = "Customer"; S wVdo|%.?  
        ViewBag.Action = "Index"; ECF \/12  
        return View("ActionName"); -+w^"R BV  
    } K3($,aB}  
pu9u b.  
    public ActionResult List() { gBCO>nJws  
        ViewBag.Controller = "Customer"; ZJeTx。Gi6  
        ViewBag.Action = "List"; !mLD`62.  
        return View("ActionName"); t:<dirw,o  
    } 'AjDB:Mt$  
} \"^.>+  
public class AdminController : Controller { !;ipLC;e}  
         "G,$Sqi@  
    public ActionResult Index() { 98^o9i  
        ViewBag.Controller = "Admin"; e$+/;MRq  
        ViewBag.Action = "Index"; l{b*YUsz>  
        return View("ActionName"); Rh.CnCbM  
    } 07:N)y,  
} W nLMa|e  
在 /Views/Shared 文件夾下再給這三個Controller添加一個共享的名為 ActionName.cshtml 的 View,代碼如下: K)d]3V!  
@{ $7bl,~Z  
    Layout = null; |KQkmc  
} v1Wz#oP  
<!DOCTYPE html> 6 s$jt-bH  
<html> /K2=GLl ;  
<head> !^EdB}@yS  
    <meta name="viewport" content="width=device-width" /> `[*nUdG  
    <title>ActionName</title> vuCl(/P`  
</head> u:FFZ  
<body> D)*OQLHW  
    <div>The controller is: @ViewBag.Controller</div> @&G< Np`  
    <div>The action is: @ViewBag.Action</div> c ii]-%J}c  
</body> lIlmXjL0  
</html> ?U PZ49y  
我們把RouteConfig.cs文件中項目自動生成的URL Rounting的定義****了,然后根據前面講的路由定義知識,我們自己寫一個最簡單的: n2#Yw}7^,o  
public static void RegisterRoutes(RouteCollection routes) { t@(`24  
    routes.MapRoute("MyRoute", "{controller}/{action}"); 609_ZW;)  
} 6HyndB^  
程序運行,URL定位到 Admin/Index 看看運行結果: _CDl9pP36#  
:jc  ?T  
這個Demo輸出的是被調用的Controller和Action名稱。 A M ZWPU  
4 給片段變量定義默認值 >P/Nb]C  
在上面我們必須把URL定位到特定Controller和Action,否則程序會報錯,因為MVC不知道去執行哪個Action。 我們可以通過指定默認值來告訴MVC當URL沒有給出對應的片段時使用某個默認的值。如下給controller和action指定默認值: #r ;;d(  
routes.MapRoute("MyRoute", "{controller}/{action}",  new { controller = "Home", action = "Index" }); g[d.lJ=Q-N  
這時候如果在URL中不****action片段的值或不****controller和action兩個片段的值,MVC將使用路由定義中****的默認值: ]U8VU  
| <q9Ee  
它的各種匹配情況如下表所示: V #Px  
?pAO?5Z:}  
注意,對于上面的URL路由的定義,我們可以只給action一個片段指定默認值,但是不能只給controller一個片段指定默認值,即如果我們給Controller指定了默認值,就一定也要給action指定默認值,否則URL只有一個片段時,這個片段匹配給了controller,action將找不到匹配。 lW!}OzE(m  
5 定義靜態片段 wCwJ#-z.=  
并不是所有的片段都是用來作為匹配變量的,比如,我們想要URL加上一個名為Public的固定前綴,那么我們可以這樣定義: +?!x;qS^  
routes.MapRoute("", "Public/{controller}/{action}",  new { controller = "Home", action = "Index" }); 。1&~@e%=-  
這樣,請求的URL也需要一個Public前綴與之匹配。我們也可以把靜態的字符串放在大括號以外的任何位置,如: ba-J-G@YW  
routes.MapRoute("", "X{controller}/{action}",  new { controller = "Home", action = "Index" }); PU6Sa-fQ2,  
在一些情況下這種定義非常有用。比如當你的網站某個鏈接已經被用戶普遍記住了,但這一塊功能已經有了一個新的版本,但調用的是不同名稱的controller,那么你把原來的controller名稱作為現在controller的別名。這樣,用戶依然使用他們記住的URL,而導向的卻是新的controller。如下使用Shop作為Home的一個別名:  GT)63|  
routes.MapRoute("ShopSchema", "Shop/{action}",  new { controller = "Home" }); 4KkjBPV  
這樣,用戶使用原來的URL可以訪問新的controller: aNLkkkJg<;  
}c"1;C&{  
6 自定義片段變量 EPZ^I)  
自定義片段變量的定義和取值 SREe, e\  
contrlloer和action片段變量對MVC來說有著特殊的意義,在定義一個路由時,我們必須有這樣一個概念:contrlloer和action的變量值要么能從URL中匹配得到,要么由默認值****,總之一個URL請求經過路由系統交給MVC****時必須保證contrlloer和action兩個變量的值都有。當然,除了這兩個重要的片段變量,我們也可從通過自定義片段變量來從URL中得到我們想要的其它信息。如下自定義了一個名為Id的片段變量,而且給它定義了默認值: 45u\v2,C3  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", z`^DQ8+\j  
    new{ ygvX}q  
        controller = "Home", c~1X /,biA  
        action = "Index", sU/R$Nbr  
        id = "DefaultId"}); pnvHh0ck_  
}); y$]gmg  
我們在HomeController中增加一個名為CustomVariable的ACtion來演示一下如何取自定義的片段變量: F>0[v|LG  
publicActionResult CustomVariable() { i09w(k?  
    ViewBag.Controller = "Home"; nJvDkh#h1  
    ViewBag.Action = "CustomVariable"; "K"]/3`k-  
    ViewBag.CustomVariable = RouteData.Values["id"]; cNX0.7Ls  
    return View("ActionName"); QEavb h^S  
} >~g(acH%`x  
可以通過 RouteData.Values[segment] 來取得任意一個片段的變量值。 (\Iz(N["G  
再稍稍改一下ActionName.cshtml 來看一下我們取到的自定義片段變量的值: {G+pI2^  
... }w#Ek=,s#o  
<div>The controller is: @ViewBag.Controller</div> hr+,-j  
<div>The action is: @ViewBag.Action</div> |b@H]c;"  
<div>The custom variable is: @ViewBag.CustomVariable</div>... 5i+0GN3nd  
將URL定位到 /Home/CustomVariable/Hello 將得到如下結果: |HjoaN)  
^k'?e"[gTs  
自定義的片段變量用處很大,也很靈活,下面介紹一些常見的用法。 5,>Of~YN  
7 將自定義片段變量作為Action方法的參數 Ag>E%N  
我們可以將自定義的片段變量當作參數傳遞給Action方法,如下所示: rcC}4mNe  
public ActionResult CustomVariable(string id) { PJ=N.x f}  
    ViewBag.Controller = "Home"; %7X<:f|N8x  
    ViewBag.Action = "CustomVariable"; =1JS6~CTLN  
    ViewBag.CustomVariable =id; |NbF3 fD  
    return View("ActionName"); [|=#~(yYQ  
} n>)'!   
效果和上面是一樣的,只不過這樣省去了用 RouteData.Values[segment] 的方式取自定義片段變量的麻煩。這個操作背后是由模型綁定來****的 & *^FBJEa。  
8 指定自定義片段變量為可選 kHO2&"6  
指定自定片段變量為可選,即在URL中可以不用指定片段的值。如下面的定義將Id定義為可選: wIrjWU2  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { qfO=_z ES  
        controller = "Home", +s*OZ6i [  
        action = "Index", X>[x7t:  
        id=UrlParameter.Optional ^V DJGBk  
}); 5}4f[   
定義為可選以后,需要對URL中沒有Id這個片段值的情況進行****,如下: +h64idM{U  
public ActionResult CustomVariable(string id) { \(nb >K  
    ViewBag.Controller = "Home"; jm-J_o;}z6  
    ViewBag.Action = "CustomVariable"; %uuh+@/&yz  
    ViewBag.CustomVariable = id == null ? "<no value>" : id; y^rcUPLT  
    return View("ActionName"); B?Vr9H7n  
} B8jSdlvz  
當Id是整型的時候,參數的類型需要改成可空的整型(即int? id)。 'IorjR@ 40  
為了省去判斷參數是否為空,我們也可以把Action方法的id參數也定義為可選,當沒有****Id參數時,Id使用默認值,如下所示: W\'njN  
public ActionResult CustomVariable(string id = "DefaultId") { A@8Ot-t:\2  
    ViewBag.Controller = "Home"; & C~R*  
    ViewBag.Action = "CustomVariable"; >-2eZ(n)"  
    ViewBag.CustomVariable = id; D 8nt%vy  
    return View("ActionName"); Xq3n7d.  
} xiu?BP?V  
這樣其實就是和使用下面這樣的方式定義路由是一樣的: 4"OUmh9LHB  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); v v2N;/;I  
9 定義可變數量的自定義片段變量 p2c4 <f-M  
我們可以通過 catchall 片段變量加 * 號前綴來定義匹配任意數量片段的路由。如下所示: ^2gDhoO_  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", )KZ1Z$<  
new { controller = "Home", action = "Index",  id = UrlParameter.Optional }); a@|/D\C  
這個路由定義的匹配情況如下所示: o/EN3J  
6^W6As0  
使用*catchall,將匹配的任意數量的片段,但我們需要自己通過“/”分隔catchall變量的值來取得獨立的片段值。 $/\b`ID  
10 路由約束 b#**`Y  
正則表達式約束 16iy miLz&  
通過正則表達式,我們可以制定限制URL的路由規則,下面的路由定義限制了controller片段的變量值必須以 H 打頭:  0p8Z l  
我們可以用正則表達式約束來定義只有指定的幾個特定的片段值才能進行匹配,如下所示: |4UU`J9M  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", \htL\m^$9  
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, _%HpB=  
    new { controller = "^H.*", action = "^Index$|^About$" } XA cpLj]  
); +%Vbz7+!  
這個定義,限制了只能訪問controller以H打著的,action片段值只能是Index或About,不區分大小寫。 $ae*3L>5M  
Http請求方式約束 E$$pO.\  
我們還可以限制路由只有當以某個特定的Http請求方式才能匹配。如下限制了只能是Get請求才能進行匹配: =)56]ki}  
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", +]n。uA-`[a  
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, Hx}K w S  
    new { controller = "^H.*", httpMethod = new HttpMethodConstraint("GET") } mhp&; Q9  
); QN%w\ JXS  
通過創建一個 HttpMethodConstraint 類的實例來定義一個Http請求方式約束,構造函數傳遞是允許匹配的Http方法名。這里的httpMethod屬性名不?***娑ǖ模皇俏飼幀?span style="display:none"> N=qe*Rlf  
這種約束也可以通過HttpGet或HttpPost過濾器來實現。 #z|\AmZ\  
自定義路由約束 s]=s2.=  
如果標準的路由約束滿足不了你的需求,那么可以通過實現 IRouteConstraint 接口來定義自己的路由約束規則。 go, Hfb  
我們來****一個限制瀏覽器版本訪問的路由約束。在MVC工程中添加一個文件夾,取名Infrastructure,然后添加一個 UserAgentConstraint 類文件,代碼如下: ~|j:xM(i  
public class UserAgentConstraint : IRouteConstraint { ; Q-f6)+&  
         GCxtWFXH  
    private string requiredUserAgent; ]J^ 9iDTTA  
eqt+EiH   
    public UserAgentConstraint(string agentParam) { 9/lCW  
        requiredUserAgent = agentParam; O[p;IG`  
    } L  lP  
8:Yha4<Bv7  
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, }*!7 Vrep  
        RouteValueDictionary values, RouteDirection routeDirection) { [OI&_WIw  
             >Z#=<  
        return httpContext.Request.UserAgent != null ^*7~ Wxk5  
            && httpContext.Request.UserAgent.Contains(requiredUserAgent); JPS7L} Kv  
    } 4X2XSK4  
} #;bpxz1lR9  
這里實現IRouteConstraint的Match方法,返回的bool值告訴路由系統請求是否滿足自定義的約束規則。我們的UserAgentConstraint類的構造函數接****一個瀏覽器名稱的關鍵字作為參數,如果用戶的瀏覽器包含****的關鍵字才可以訪問。接一來,我們需要****自定的路由約束: =*q|568  
public static void RegisterRoutes(RouteCollection routes) { K)2ZH@  
<B]\&  
    routes.MapRoute("ChromeRoute", "{*catchall}", ^}XKhn.S'  
        new { controller = "Home", action = "Index"}, o.tCw\M$g  
        new { customConstraint = new UserAgentConstraint("Chrome") } _VU/j9<+  
    ); 0dKI+zgr  
} Z, Kbt  
下面分別是IE10和Chrome瀏覽器請求的結果: =RR225  
r`]&{0}23  
11 定義請求磁盤文件路由 I)~&6@J n  
并不是所有的URL都是請求controller和action的。有時我們還需要請求一些資源文件,如圖片、html文件和JS庫等。 $or?7 w>  
我們先來看看能不能直接請求一個靜態Html文件。在項目的Content文件夾下,添加一個html文件,內容隨意。然后把URL定位到該文件,如下圖: $!c)%qDq  
[img]http://bbs.tietiejia.com/attachment/637_459674_42215b5d1cf9e27.png[/img 2e}${NZN  
我們看到,是可以直接訪問一靜態資源文件的。 wj>mk  
默認情況下,路由系統先檢查URL是不是請求靜態文件的,如果是,**器直接返回文件內容并結束對URL的路由解析。我們可以通過設置 RouteCollection的 RouteExistingFiles 屬性值為true 讓路由系統對靜態文件也進行路由匹配,如下所示: } d / 5_X  
public static void RegisterRoutes(RouteCollection routes) { |]a =He;  
     fI%+  
    routes.RouteExistingFiles = true; pv2_A   
o56_t{<  
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", !1f8~"Z  
        new { controller = "Home", action = "Index", id = UrlParameter.Optional [GeJn\C_?  
    }); daT[2M  
} x^aqnKoJ%\  
設置了routes.RouteExistingFiles = true后,還需要對IIS進行設置,這里我們以IIS Express為例,右鍵IIS Express小圖標,選擇“顯示所有應用程序”,彈出如下窗口: ZF :e6em  
*F+t`<2  
點擊并打****配置文件,Control+F找到UrlRoutingModule-4.0,將這個節點的preCondition屬性改為空,如下所示: JGPLVw  
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition=""/> dzZ74FE!t  
然后我們運行程序,再把URL定位到之前的靜態文件: @Md%gEh;&  
:8}QKp  
這樣,路由系統通過定義的路由去匹配RUL,如果路由中沒有定義該靜態文件的匹配,則會報上面的錯誤。 !RLg[ _'  
一旦定義了routes.RouteExistingFiles = true,我們就要為靜態文件定義路由,如下所示: ~YHy '.  
public static void RegisterRoutes(RouteCollection routes) { 27*u^N*z@  
     uhL+bj+W  
    routes.RouteExistingFiles = true; d% ?+q0j  
T Hirh6  
    routes.MapRoute("DiskFile", "Content/StaticContent.html", BP2-LG&\  
        new { controller = "Customer", action = "List", }); U0'>(FP~2  
&^e%gU8!\  
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", (OT /o&cQ  
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }); FjIS:9^)t5  
} _^Lv8a3(O  
這個路由匹配Content/StaticContent.html的URL請求為controller = Customer, action = List。我們來看看運行結果: 6_/691  
x[7jm"Pz  
這樣****的目的是為了可以在Controller的Action中控制對靜態資源的請求,并且可以阻止對一些特殊資源文件的訪問。 cZKK\hf<  
設置了RouteExistingFiles屬性為true后,我們要為允許用戶請求的資源文件進行路由定義,如果每種資源文件都去定義相應的路由,就會顯得很繁瑣。 9Vz1*4Ln  
我們可以通過RouteCollection類的IgnoreRoute方法繞過路由定義,使得某些特定的靜態文件可以由**器直接返回給給瀏覽器,如下所示: g\&[;v i  
public static voidRegisterRoutes(RouteCollection routes) { e{8z1t20:  
     6> v`6  
    routes.RouteExistingFiles = true; ";38v jIV  
%3scz)4$  
    routes.IgnoreRoute("Content/{filename}.html"); 9ctvy?53H  
`;b@a<Wl  
    routes.MapRoute("DiskFile", "Content/StaticContent.html", Ed,`1+  
        new { controller = "Customer", action = "List", }); O{a<f7 W  
ep .AW'+  
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", 1"3|6&=  
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }); mh]'/C_*<w  
} 5R}Qp<D[^  
這樣,只要是請求Content目錄下的任何html文件都能被直接返回。這里的IgnoreRoute方法將創建一個RouteCollection的實例,這個實例的Route Handler 為 StopRoutingHandler,而不是 MvcRouteHandler。運行程序定位到Content/StaticContent.html,我們又看到了之前的靜態面面了。 <jF]SN   
12 生成URL(鏈接) %o9@[o .]  
前面講的都是解析URL的部分,現在我們來看看如何通過路由系統在View中生成URL。 1VK?Svnd  
生成指向當前controller的action鏈接 ~n%~ Z|mMF  
在View中生成URL的最簡單方法就是調用Html.ActionLink方法,如下面在 Views/Shared/ActionName.cshtml 中的代碼所示: )ALPMmlRs  
... zu'Uau  
<div>The controller is: @ViewBag.Controller</div> aYr?J Ol  
<div>The action is: @ViewBag.Action</div> h`dtcJ0  
<div>    @Html.ActionLink("This is an outgoing URL", "CustomVariable") 0F-X.Dq  
</div>... $,q~q^0  
這里的Html.ActionLink方法將會生成指向View對應的Controller和第二個參數指定的Action,我們可以看看運行后頁面是如何顯示的: 9{|JmgO!  
t m ?[0@<s  
經過查看Html源碼,我們發現它生成了下面這樣的一個html鏈接: GVk&n"9kp  
<a href="/Home/CustomVariable">This is an outgoing URL</a> ;hGC.}X  
這樣看起來,通過Html.ActionLink生成URL似乎并沒有直接在View中自己寫一個<a>標簽更直接明了。 但它的好處是,它會自動根據路由配置來生成URL,比如我們要生成一個指向HomeContrller中的CustomVariable Action的連接,通過Html.ActionLink方法,只需要給出對應的Controller和Action名稱就行,我們不需要關心實際的URL是如何組織的。舉個例子,我們定義了下面的路由: \"B?'Ep;  
public static void RegisterRoutes(RouteCollection routes) { Jm$. $B&I  
             ;]zV ?9  
    routes.MapRoute("NewRoute", "App/Do{action}", new { controller = "Home"}); =LV7K8FSd  
             Ig75bZz   
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}", O,R5csMh  
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }); $X8(OS5d'  
} CY#|VE M  
運行程序,我們發現它會自動生成下面這樣的連接: =r"8J5[f  
<a href="/App/DoCustomVariable">This is an outgoing URL</a> ~Q"3#4l  
所以我們要生成指向某個Action的鏈接時,最好使用Html.ActionLink方法,否則你很難保證你手寫的連接就能定位到你想要的Action。  (n+2z"/  
生成其他controller的action鏈接 _#@n^c  
上面我們給Html.ActionLink方法傳遞的第二個參數只告訴了路由系統要定位到當前View對應的Controller下的Action。Html.ActionLink方法可以使用第三個參數來指定其他的Controller,如下所示: >(mp$#+w  
<div> A^:[+PJHN  
    @Html.ActionLink("This targets another controller", "Index", "Admin") !E!i`yF  
</div> r!SMF ]?SJ  
它會自動生成如下鏈接: K}"xZy Tm1  
<a href="/Admin">This targets another controller</a> -SZXUN  
生成帶有URL參數的鏈接 XWN ra  
有時候我們想在連接后面加上參數以傳遞數據,如 ?id=xxx 。那么我們可以給Html.ActionLink方法指定一個匿名類型的參數,如下所示: xY9 #ouF  
<div>   @Html.ActionLink("This is an outgoing URL", "CustomVariable", new { id = "Hello" }) \MBbZB9@  
</div> >QO^h<.>  
它生成的Html如下: 1Q\P] -  
<a href="/Home/CustomVariable/Hello">This is an outgoing URL</a> |S.G#za  
指定鏈接的Html屬性 |f), dC  
通過Html.ActionLink方法生成的鏈接是一個a標簽,我們可以在方法的參數中給標簽指定Html屬性,如下所示: BrF/-F  
<div> c'cK+32  
    @Html.ActionLink("This is an outgoing URL",  "Index", "Home", null, 4?Pdld  
        new {id = "myAnchorID", @class = "myCSSClass"}) m;-FP 2~  
</div> ]j> W9n?  
這里的class加了@符號,是因為class是C#關鍵字,@符號起到轉義的作用。它生成 的Html代碼如下: t80s(e  
<a class="myCSSClass" href="/"id="myAnchorID">This is an outgoing URL</a> xIu #  
生成完整的標準鏈接 f%vJmpg  
前面的都是生成相對路徑的URL鏈接,我們也可以通過Html.ActionLink方法生成完整的標準鏈接,方法如下: & $E[l'  
<div> G8=2=/ !  
    @Html.ActionLink("This is an outgoing URL", "Index", "Home",  8:=&=9%  
        "https", "myserver.mydomain.com", " myFragmentName", vD<6BQR  
        new { id = "MyId"}, )_bc:6Q  
        new { id = "myAnchorID", @class = "myCSSClass"}) AsFn%8_I  
</div> Fp'qn'){:#  
這是Html.ActionLink方法中最多參數的重載方法,它允許我們****請求的協議(https)和目標**器地址(myserver.mydomain.com)等。它生成的鏈接如下: 9U[Gh97Sf  
<a class="myCSSClass" id="myAnchorID"    href="https://myserver.mydomain.com/Home/Index/MyId#myFragmentName" >    This is an outgoing URL</a> K$v SdpC  
生成URL字符串 Zoe>Ow8mE`  
用Html.ActionLink方法生成一個html鏈接是非常有用而常見的,如果要生成URL字符串(而不是一個Html鏈接),我們可以用 Url.Action 方法,使用方法如下: ^b|Z<oF  
<div>This is a URL: J{>9ctN  
    @Url.Action("Index", "Home", new { id = "MyId" }) .Zo %6[X  
</div> ,fWQSc\}  
它顯示到頁面是這樣的: 9/A$ 3#wF  
$!Z><&^/  
根據指定的路由名稱生成URL : 5)Dn87  
我們可以根據某個特定的路由來生成我們想要的URL,為了更好說明這一點,下面給出兩個URL的定義: ,n\"zYf ]^  
public static void RegisterRoutes(RouteCollection routes) { |;xm- AM4r  
    routes.MapRoute("MyRoute", "{controller}/{action}"); @z $,KUH  
    routes.MapRoute("MyOtherRoute", "App/{controller}/{action}", new { controller = "Home" }); 8Aq [@i  
} HIiMq'H^  
對于這樣的兩個路由,對于類似下面這樣的寫法: $t*>A+J  
@Html.ActionLink("Click me", "Index", "Customer") GJZGHUB=>  
始終會生成這樣的鏈接: 6Gt~tlt:L  
<a href="/Customer/Index">Click me</a> <Q57}[$*)  
也就是說,永遠無法使用第二個路由來生成App前綴的鏈接。這時候我們需要通過另一個方法Html.RouteLink來生成URL了,方法如下: &O|!w&  
  @Html.RouteLink("Click me", "MyOtherRoute", new {controller="Customer",action="Index" }); 0$=Uhi  
它會生成如下鏈接: tW<i;2 l  
<a Length="8" href="/App/Customer/Index">Click me</a> D#%aow'(7  
這個鏈接指向的是HomeController下的Index Action。但需要注意,通過這種方式來生成URL是不****的,因為它不能讓我們從直觀上看到它生成的URL指向的controller和action。所以,非到萬不得已的情況才會這樣用。 SCwAAE9s]  
在Action方法中生成URL %v}SJEXF p  
通常我們一般在View中才會去生成URL,但也有時候我們需要在Action中生成URL,方法如下: k+-IuO  
Public ViewResult MyActionMethod() { -,xCUG<g  
     t<~WDI|AN  
    string myActionUrl = Url.Action("Index", new { id = "MyID" }); v[$-)vs*ag  
    string myRouteUrl = Url.RouteUrl(new { controller = "Home", action = "Index" }); (<M^C>pldf  
     %>,B1nt  
    //... do something with URLs... 3=[#(p:  
    return View(); 6yDj1PI  
} E`E$ }iLs  
其中 myActionUrl 和 myRouteUrl 將會被分別賦值 /Home/Index/MyID 和 / 。 oJ\)-qSf  
更多時候我們會在Action方法中將客戶端瀏覽器重定向到別的URL,這時候我們使用RedirectToAction方法,如下: }iGpuoXT`  
public RedirectToRouteResultMyActionMethod() { ~bm VpoI  
    return RedirectToAction("Index"); !-G'8a|7  
} l>( w]  
RedirectToAction的返回結果是一個RedirectToRouteResult類型,它使MVC觸發一個重定向行為,并調用指定的Action方法。RedirectToAction也有一些重載方法,可以傳入controller等信息。也可以使用RedirectToRoute方法,該方法傳入的是object匿名類型,易讀性強,如: Xk2M.:3`  
publicRedirectToRouteResult MyActionMethod() { ! z!lQ~  
    return RedirectToRoute(new { controller = "Home", action = "Index", id = "MyID"}); J#k3iE }  
} %62W[Oh5  
,/m@<NyK  
13 URL方案最佳實踐 8PN/*Sa  
g>k"R4  
下面是一些使用URL的建議: _:R Q9x'  
最好能直觀的看出URL的意義,不要用應用程序的具體信息來定義URL。比如使用 /Articles/Report 比使用 /Website_v2/CachedContentServer/FromCache/Report 好。 yQP!Vt^  
U,G!u=+  
翰用內容標題比使用ID好。比如使用 /Articles/AnnualReport 比使用 /Articles/2392 好。如果一定要使用使用ID(比如有時候可能需要區分相同的標題),那么就兩者都用,如 /Articles/2392/AnnualReport ,它看起來很長,但對用戶更友好,而且更利于SEO。 B: '}SA{  
C-wwQbdG/  
對于Web頁面不要使用文件擴展名(如 .aspx 或 .mvc)。但對于特殊的文件使用擴展名(如 .jpg、.pdf 和 .zip等)。 R,Gr{"H  
W|~Jl7hs8Q  
盡可能使用層級關系的URL,如 /Products/Menswear/Shirts/Red,這樣用戶就能猜到父級URL。 BIu%A]e"  
t=-t xnlr<  
不區分大小寫,這樣方便用戶輸入。 iTX:*$~I  
B/:+(|  
揰湫罸用Get和Post。Get一般用來從**器獲取只讀的信息,當需要操作更改狀態時使用Post。 B~%'YQk  
jwP}{mi*  
盡可能避免使用標記符號、代碼、字符序列等。如果你想要用標記進行分隔,就使用中劃線(如 /my-great-article),下劃線是不友好的,另外空格和+號都會被URL編碼。 tYe+7s  
>rbHpLm1`  
不要輕易改變URL,尤其對于互聯網網站。如果一定要改,那也要盡可能長的時間保留原來的URL。 m7dpr$J  
K;n2mXYGM  
盡量讓URL使用統一的風格或習慣。 7m4gGkX#r  
注以上內容來自于:《Pro ASP.NET MVC 4 4th Edition》 knX*fp  
fX:)mLnO/  
附:RouterDebugger安裝使用說明 : MC 8t"SB  
1.安裝 rNi]|)-ET  
在程序包控制臺中執行命令 ">8]Oi;g  
PM> Install-Package routedebugger G,{=sFX  
安裝成功后Web.config文件中會自動加入行 c `[,>  
<add key="RouteDebugger:Enabled"value="true" /> ^)JUl!5j]C  
2.使用 xJ-(]cO'  
MVC3中需要在文件Global.asax中 Application_Start() 中添加代碼 PreApplicationStart.Start();  MV**** 以后不需要 cWNZ +Q8Y  
如下樣式: T(GEFnt Y  
protected voidApplication_Start() { )aV\=a |A  
RegisterRoutes(RouteTable.Routes); .5S< G)Ja  
PreApplicationStart.Start(); //....... } X0QY:?  
3.禁用 $uPM.mPFE  
web.config中 s8r|48I#;  
<add key="RouteDebugger:Enabled" value="true" /> 4R c_C0O  
改為 /Zzb7bHLK  
<add key="RouteDebugger:Enabled" value="false" /> ?Aq \Gr  
4.運行效果 %OV)O-  
tom1u>1n  
RouteDebuger見附件:鏈接: -a[[1  
密碼:
本部分內容設定了隱藏,需要回復后才能看到
m'!smS x8  
此課程系 我本人的大型商業課程《基于ASP.NET MVC 4 +Knockout.JS+Web API+FluentData+EasyUI 技術實現Web通用商業****發框架》中 項目預備知識部分的 |9fvj6?Y  
課程四《ASP.NET MV**** 核心技術教程》中的《專題三、實例快速上手 - ASP.NET MV**** URL Routing 深入與使用URL最佳實踐》 x|7vN E=Q  
整套課程預計7月份內上線預****,敬請關注北風官網! n?UFFi+a  
此章節視頻目錄如下: H'2J!/V  
! R b  
此處公****前兩講,需要更多資源的同學可以給我留言 !nm[ZrS P  
(O[:-Aqm  
Fm{/&U^  
O<*l"fw3  
級別: 北風愛好者

UID: 476548
精華: 0
發帖: 3
威望: 6 點
學點: 1 點
貢獻: 0 點
好評: 0 點
學幣: 0 個
注冊時間: 2014-07-18
最后登錄: 2016-11-21
沙發(1樓)  發表于: 2014-07-18 11:43||

別搞得那么經典好不
級別: VIP五級

UID: 270178
精華: 0
發帖: 21
威望: 449 點
學點: 491 點
貢獻: 48 點
好評: 0 點
學幣: 8 個
注冊時間: 2010-11-11
最后登錄: 2018-06-07
板凳(2樓)  發表于: 2014-07-22 10:55||

期待MV****+EasyUI+FluentData的新課程!
級別: 北風愛好者

UID: 493021
精華: 0
發帖: 5
威望: 5 點
學點: 0 點
貢獻: 0 點
好評: 0 點
學幣: 0 個
注冊時間: 2014-08-24
最后登錄: 2014-08-24
地板(3樓)  發表于: 2014-08-24 23:11||

點贊!!
級別: 北風愛好者

UID: 493021
精華: 0
發帖: 5
威望: 5 點
學點: 0 點
貢獻: 0 點
好評: 0 點
學幣: 0 個
注冊時間: 2014-08-24
最后登錄: 2014-08-24
地下室(4樓)  發表于: 2014-08-24 23:16||

感謝分享
級別: VIP三級

UID: 90325
精華: 0
發帖: 3
威望: 2 點
學點: 11 點
貢獻: 0 點
好評: 0 點
學幣: 0 個
注冊時間: 2008-12-07
最后登錄: 2016-11-11
下水道(5樓)  發表于: 2014-09-12 15:16||

吐血支持
級別: 北風愛好者

UID: 495644
精華: 0
發帖: 3
威望: 29 點
學點: 36 點
貢獻: 3 點
好評: 0 點
學幣: 1 個
注冊時間: 2014-08-30
最后登錄: 2014-09-12
6樓  發表于: 2014-09-12 21:34||

前來認真學習一下了。
級別: 北風工程師

UID: 470673
精華: 0
發帖: 3
威望: 2297 點
學點: 2316 點
貢獻: 251 點
好評: 0 點
學幣: 19 個
注冊時間: 2014-06-29
最后登錄: 2015-06-06
7樓  發表于: 2014-09-13 10:42||

好東西值得學習
級別: 北風技術菜鳥

UID: 125044
精華: 0
發帖: 13
威望: 37 點
學點: 36 點
貢獻: 2 點
好評: 0 點
學幣: 1 個
注冊時間: 2009-02-25
最后登錄: 2014-09-13
8樓  發表于: 2014-09-13 15:02||

.......
級別: VIP四級

UID: 460455
精華: 0
發帖: 4
威望: 4 點
學點: 13 點
貢獻: 0 點
好評: 0 點
學幣: 0 個
注冊時間: 2014-04-08
最后登錄: 2014-10-17
9樓  發表于: 2014-09-29 16:51||

期待課程
上一主題下一主題
«123»Pages: 1/3     Go
吉林快3计划 2019免费网赚资源 网赚平台排行榜 澳门手机网投 做什么网赚好呢 159彩票 金旋网赚 贵州快3 互联网赚钱 香港开奖结果2019+开奖结果