艾伟_转载:[一步一步MVC]第四回:漫谈ActionLink,有时“胡搅蛮缠”

本系列文章导航

[一步一步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的扩展方法,我们可以从智能感知提示中最直观的得到了解:

显然,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有了个大致的了解,对于更好的应用是有好处的。那么,今天就说到这里。

时间: 2024-07-29 11:23:36

艾伟_转载:[一步一步MVC]第四回:漫谈ActionLink,有时“胡搅蛮缠”的相关文章

艾伟_转载:学习 ASP.NET MVC (第一回)理论篇

本系列文章导航 学习 ASP.NET MVC (第一回)理论篇 学习 ASP.NET MVC (第二回)实战篇 学习 ASP.NET MVC (第三回)实战篇 学习 ASP.NET MVC (第四回)实战篇 学习 ASP.NET MVC (第五回)理论篇 MVC三种角色:--Model:用于存储数据的组件--View:根据Model数据进行内容展示的组件--Controller:接受并处理用户指令(操作Model),选择一个View并输出内容.Controller对View进行引用,但是View

艾伟_转载:学习 ASP.NET MVC (第五回)理论篇

本系列文章导航 学习 ASP.NET MVC (第一回)理论篇 学习 ASP.NET MVC (第二回)实战篇 学习 ASP.NET MVC (第三回)实战篇 学习 ASP.NET MVC (第四回)实战篇 学习 ASP.NET MVC (第五回)理论篇 通过前几篇文章,我们通过ASP.NET MVC创建了一个简单的应用程序,学习了ASP.NET MVC的基本框架和工作流程.但是Demo中很多东西都是VS为我们自动生成的,比如View的html代码等.此文和大家一起学习一下ASP.NET MVC

艾伟_转载:学习 ASP.NET MVC (第四回)实战篇

本系列文章导航 学习 ASP.NET MVC (第一回)理论篇 学习 ASP.NET MVC (第二回)实战篇 学习 ASP.NET MVC (第三回)实战篇 学习 ASP.NET MVC (第四回)实战篇 学习 ASP.NET MVC (第五回)理论篇 我们继续ASP.NET MVC之旅.上文中我们实现了对User信息的展示,详细信息的列表,还有错误页的实现.本文继续完成添加,修改,删除的操作.首先我们来完成Controller的代码: Code//        // GET: /Users

艾伟_转载:[一步一步MVC]第六回:什么是MVC(上)?

本系列文章导航 [一步一步MVC]第一回:使用ActionSelector控制Action的选择 [一步一步MVC]第二回:还是ActionFilter,实现对业务逻辑的统一Authorize处理 [一步一步MVC]第三回:MVC范例大观园 [一步一步MVC]第四回:漫谈ActionLink,有时"胡搅蛮缠" [一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper [一步一步MVC]第六回:什么是MVC(上)? 引言 所谓MVC,其实就是M.V.C而已.归根揭底,

艾伟_转载:[一步一步MVC]第二回:还是ActionFilter,实现对业务逻辑的统一Authorize处理

本系列文章导航 [一步一步MVC]第一回:使用ActionSelector控制Action的选择 [一步一步MVC]第二回:还是ActionFilter,实现对业务逻辑的统一Authorize处理 [一步一步MVC]第三回:MVC范例大观园 [一步一步MVC]第四回:漫谈ActionLink,有时"胡搅蛮缠" [一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper [一步一步MVC]第六回:什么是MVC(上)? 由问题引出 在ASP .NET MVC中,以友好的U

艾伟_转载:[一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper

本系列文章导航 [一步一步MVC]第一回:使用ActionSelector控制Action的选择 [一步一步MVC]第二回:还是ActionFilter,实现对业务逻辑的统一Authorize处理 [一步一步MVC]第三回:MVC范例大观园 [一步一步MVC]第四回:漫谈ActionLink,有时"胡搅蛮缠" [一步一步MVC]第五回:让TagBuilder丰富你的HtmlHelper [一步一步MVC]第六回:什么是MVC(上)? 对HtmlHelper进行扩展,是MVC中对于Vie

艾伟_转载:把委托说透(1):开始委托之旅 委托与接口

委托,本是一个非常基础的.NET概念,但前一阵子在园子里却引起轩然大波.先是Michael Tao的随笔让人们将委托的写法与茴香豆联系到了一起,接着老赵又用一系列文章分析委托写法的演变,并告诫"嘲笑孔乙己的朋友们,你们在一味鄙视"茴"的四种写法的同时,说不定也失去了一个了解中国传统文化的机会呢!". 在我个人看来,委托是.NET Framework中一个非常炫的特性,绝不会向有些评论里说的那样,根本没有机会接触.恰恰相反,我们几乎每天都会接触委托,使用委托. 其实园

艾伟_转载:正则表达式30分钟入门教程

  本文目标 30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它. 如何使用本教程 最重要的是--请给我30分钟,如果你没有使用正则表达式的经验,请不要试图在30秒内入门--除非你是超人 :) 别被下面那些复杂的表达式吓倒,只要跟着我一步一步来,你会发现正则表达式其实并没有你想像中的那么困难.当然,如果你看完了这篇教程之后,发现自己明白了很多,却又几乎什么都记不得,那也是很正常的--我认为,没接触过正则表达式的人在看完这篇教程后,能把提到过的语法记住8

艾伟_转载:使用LINQ to SQL更新数据库(中):几种解决方案

在前一篇文章中,我提出了在使用LINQ to SQL进行更新操作时可能会遇到的几种问题.其实这并不是我一个人遇到的问题,当我在互联网上寻找答案时,我发现很多人都对这个话题发表过类似文章.但另我无法满足的是,他们尽管提出了问题,却没有进行详细的剖析,只给出了解决方案(如添加RowVersion列.去除关联等),但却没有说明为什么必须这么做.这也是我写上篇的初衷,希望通过对LINQ to SQL源代码的分析,来一步一步找出解决问题的办法.本文将对这些方法一一进行讨论. 方案一:重新赋值 在Terry