[一步一步MVC]第四回:漫談ActionLink,有時“胡攪蠻纏”

作者: Anytao  來源: 博客園  發布時間: 2010-01-13 11:29  閱讀: 2515 次  推薦: 0   原文鏈接   [收藏]  

系列文章導航:

[一步一步MVC]第一回:使用ActionSelector控制Action的選擇

[一步一步MVC]第二回:還是ActionFilter,實現對業務邏輯的統一Authorize處理

[一步一步MVC]第三回:MVC范例大觀園

[一步一步MVC]第四回:漫談ActionLink,有時“胡攪蠻纏”

[一步一步MVC]第五回:讓TagBuilder豐富你的HtmlHelper

[一步一步MVC]第六回:什么是MVC(上)?

 

MVC時代來臨了,但是一開始是不被很多人接受的。可能的主要原因是,大家不得不告別拖拉控件的至爽感受,回到貌似asp的歷史歲月。所以,心有不甘是可以理解的,然而時代顯然是進步的。我們雖然必須在View中進行很多HTML代碼的工作,但是MVC為我們提供了可以堪稱完美的方案(至少我是這樣認為的),那就是HtmlHelper。在MVC的View層,我們有很多熟悉的面孔,例如Html.Encode、Html.AntiForgeryToken、Html.BeginForm、Html.TextBox等,而其中ActionLink算是其中的“猛將兄”。

淺議HtmlHelper

簡單的說,HtmlHelper就是一個封裝了ViewContext、IViewDataContainer、RouteCollection等上下文信息的一籮筐靜態方法類(注,HtmlHelper本身并不是靜態類),其中包含了我們上文介紹的熟悉身影Encode、AntiForgeryToken等,但不包含BeginForm、TextBox,當然也不包括ActionLink,其原因是BeginForm、TextBox、ActionLink其實是HtmlHelper的擴展方法,我們可以從智能感知提示中最直觀的得到了解:

o_anytao_mvc_07_actionlinktalk_01[1]

顯然,ActionLink和Encode的智能提示標記是有區別的。

所以,HtmlHelper其實很簡單,而通過Extension Methods對其的“功能注入”機制實現了極大的擴展空間。而且,HtmlHelper封裝了ViewContext、RouteCollection等上下文信息,為實現擴展帶來便利。所以,順便提一下,這也正是老趙同志在為視圖自定義輔助方法(上)中實現JQueryHelper時引入相應元素(ViewContext、RouteCollection、ViewPage),有著異曲同工之妙,所以HtmlHelper并不是唯一的選擇,高興的話,你也可以類似于AnytaoHelper之類的東東。

所以,通過HtmlHelper就可在運行時動態生成HTML代碼,其實我們在WebForm時代就經常玩兒這種“陰招”,然而在HtmlHelper這里,顯然已經發揚光大了。例如老趙的JQueryHelper就通過一系列的包裝,省去了對validation的麻煩語法。

同時,擴展HtmlHelper其實及其簡單。例如:

 

 
// Release : code01, 2009/04/30
// Author : Anytao, http://www.anytao.com
public static string Label(this HtmlHelper helper, string name, string value)
{

return string.Format("{1}
", name, value);
}

 

通過下面的方式就可以調用該方法了:

同樣的道理,當我們攤開ActionLink的實現具體實現時,可見:

 

 
public static string ActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes) {
if (String.IsNullOrEmpty(linkText)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}


string targetUrl = UrlHelper.GenerateUrl(null, actionName, controllerName, routeValues, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true /* includeImplicitMvcValues */);

return GenerateLink(linkText, targetUrl, GetAjaxOptions(ajaxOptions), htmlAttributes);
}

 

ActionLink其實根據Action、Controller、linkText信息,通過GenerateLink生成了我們需要的HTML代碼,我們將在下面繼續看到影響GenerateLink的還有Route信息。

有時“胡攪蠻纏”

聊了半天HtmlHelper,該說說ActionLink了。正如前文而言,ActionLink僅僅是HtmlHelper的擴展方法而已。不過,雖然ActionLink平易近人,但是還是在不經意間發現其胡攪蠻纏的地方。我們先按下不表來看看如何使用ActionLinks,MVC Framework為我們提供了兩種方式:

  • ActionLink
  • ActionLink

顯而易見,一種是非泛型方法,通過參數方式調用,沒有強類型優勢;另一種是泛型方法,可以通過強類型調用,不過如果通過ActionName對Action進行重寫標記時,泛型ActionLink是不可用的,我在《還是ActionFilter,實現對業務邏輯的統一Authorize處理》已進行過討論了。

具體而言,上述參數主要包括:

  • Edit,為linkText,具體而言就是顯示的字符串;
  • Edit,對應為ActionName;
  • Book,為Controller;
  • new { id = Model.ID },為生成元素的id定義;
  • new { @class = “BookDetail” },則為元素添加了tag要素。

具體的執行邏輯不是我們關心的問題,而上述代碼生成的Source Code,則對應為:

<a class="BookDetail" href="/Book/Edit/1">Edit a>

而如果應用泛型ActionLink,則上述調用將變成:

 

生成同樣的Source Code,不過通常情況下,我們還是推薦泛型ActionLink,至少有類型安全、代碼優雅的優點。

注:既然是ActionLink,文如其名,我們不能將其濫用,也就是說涉及Action的Links時可以考慮用ActionLink,其他情況下最好還是手寫自己的鏈接代碼或者擴展自己的HtmlHelper等。

然而,在有些情況下,假設我們有如下Route:

 

 
// Release : code02, 2009/04/30
// Author : Anytao, http://www.anytao.com
routes.MapRoute(
"BookRoute",
"Tao/Book/id",
new { controller = "Book", action = "Detail", id = "" }
);

 

當我們使用

 

調用BookController下的Detail Action,不過令我們奇怪的是,生成Html代碼并不如期望的那樣,而是:

<a href="/Tao/Book/id">Book<a>

顯然,ActionLink有點兒“胡攪蠻纏”了。其原因在于,新定義的BookRoute改寫了ActionLink的“既有”行為,本來我們期望的是:

<a href="/Book/Detail/id">Book< a>

為了追查原因,我們將對ActionLink進行了必要的調查,首先了解ActionLink的定義:

public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName)

而ActionLink的具體實現中,我們看到了routeCollection的GetVirtualPath方法中涉及了對">">Dictionary<string, RouteBase>的操作,所以不言而喻,ActionLink生成的Url是受routeCollection影響的。對于其“胡攪蠻纏”,我相信這就是原因吧。

所以,雖是一個小小的意外,但是了解了就不是意外。對于我們的應用而言,有兩點值得注意:

  • 注意Route定義對于ActionLink可能造成的影響。
  • 在這種情況下,我們可以考慮放棄ActionLink,而通過全手動方式實現:
<a href="Book/Detail/ ">Book<a>

不償為一種回歸原始的方式,不是嗎?

本文調侃了題目,但是更重要的事情是我們對HtmlHelper及ActionLink有了個大致的了解,對于更好的應用是有好處的。那么,今天就說到這里。

 
0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()