ASP.NET 路由系統通過注冊的路由表旨在實現兩個“方向”的路有功能,即針對入棧請求的路由和出棧URL的生成。前者通過調用代表全局路由表的RouteCollection對象的GetRouteData方法實現,後者則依賴於RouteCollection的GetVirtualPathData方法,而最終還是落在繼承自RouteBase的路由對象的同名方法的調用上。為了編程的方面,ASP.NET MVC為了設計了HtmlHelper和UrlHelper這兩個幫助類,我們可以通過調用它們的ActionLink/RouteLink和Action/RouteUrl根據注冊的路有規則生成鏈接或者URL。從本質上講,HtmlHelper/UrlHelper實現的對URL的生成最終還是依賴於上面所說的GetVirtualPathData方法。
一、UrlHelper V.S. HtmlHelper
在介紹如果通過HtmlHelper和UrlHelper來生成鏈接或者URL之前,我們來先來看看它們的基本定義。從下面給出的代碼片斷我們可以看出UrlHelper對象實際上對一個表示請求上下文的RequestContext和路由對象集合的RouteCollection對象的封裝。它們分別對應於只讀屬性RequestContext和RouteCollection,並且在構造函數中被初始化。如果在構造UrlHelper的時候沒有指定RouteCollection對象,那麼通過RouteTable的靜態屬性Routes表示的全局路有表將直接被使用。
1: public class UrlHelper
2: {
3: //其他成員
4: public UrlHelper(RequestContext requestContext);
5: public UrlHelper(RequestContext requestContext, RouteCollection routeCollection);
6:
7: public RequestContext RequestContext { get; }
8: public RouteCollection RouteCollection { get;}
9: }
再來看看如下所示的HtmlHelper的定義,它同樣具有一個表示路由對象集合的RouteCollection屬性。和UrlHelper一樣,如果在構造函數沒有顯示指定,那麼RouteTable的靜態屬性Routes表示的RouteCollection對象將會用於初始化該屬性。
1: public class HtmlHelper
2: {
3: //其他成員
4: public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer);
5: public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection);
6:
7: public RouteCollection RouteCollection { get; }
8: public ViewContext ViewContext { get; }
9: }
10: public class ViewContext : ControllerContext
11: {
12: //省略成員
13: }
14: public class ControllerContext
15: {
16: //其他成員
17: public RequestContext RequestContext { get; set; }
18: public virtual RouteData RouteData { get; set; }
19: }
由於HtmlHelper只要在View中使用,所以它具有一個通過ViewContext屬性表示的針對View的上下文。至於該屬性對應的類型ViewContext,它是表示Controller上下文的ControllerContext的子類,而後者通過RequestContext和RouteData屬性提供當前的請求上下文和路由數據(其實RouteData屬性表示的RouteData對象已經包含在RequestContext屬性表示的RequestContext對象中)。
二、UrlHelper.Action V.S. HtmlHelper.ActionLink
UrlHelper和HtmlHelper分別通過Action和ActionLink方法用於生成一個針對某個Controller的某個Action的URL和鏈接。下面的代碼片斷列出了UrlHelper的所有Action重載,參數actionName和controllerName分別代表Action和Controller的名稱。通過object或者RouteValueDictionary類型表示的routeValues參數表示替換URL模板中變量的變量值。參數protocol和hostName代表作為完整URL的傳輸協議(比如http和https等)以及主機名。
1: public class UrlHelper
2: {
3: //其他成員
4: public string Action(string actionName);
5: public string Action(string actionName, object routeValues);
6: public string Action(string actionName, string controllerName);
7: public string Action(string actionName, RouteValueDictionary routeValues);
8: public string Action(string actionName, string controllerName, object routeValues);
9: public string Action(string actionName, string controllerName, RouteValueDictionary routeValues);
10:
11: public string Action(string actionName, string controllerName, object routeValues, string protocol);
12: public string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName);
13: }
對於定義在UrlHelper中的眾多Action方法,如果我們顯示指定了傳輸協議(protocol參數)或者主機名稱,返回的是一個完整的URL;否則返回的是一個相對URL。如果我們沒有顯示地指定Controller的名稱(controllerName參數),那麼當前Controller的名稱被采用。對於UrlHelper來說,通過RequestContext屬性表示的當前請求上下文包含了相應的路由信息,即RequestContext的RouteData屬性表示的RouteData。RouteData的Values屬性中必須包含一個Key為“controller”的元素,其值就代表當前Controller的名稱。
在System.Web.Mvc.Html.LinkExtensions中,我們為HtmlHelper定義了如下所示的一系列ActionLink方法重載。顧名思義,ActionLink不再僅僅返回一個URL,而是生成一個鏈接(<a>...</a>),但是其中作為目標URL的生成邏輯和UriHelper是完全一致的。
1: public static class LinkExtensions
2: {
3: //其他成員
4: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName);
5: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues);
6: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName);
7: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues);
8: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes);
9: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes);
10: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes);
11: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName,RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes);
12: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes);
13: public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes);
14: }