zoukankan      html  css  js  c++  java
  • 艾伟_转载:[一步一步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的扩展方法,我们可以从智能感知提示中最直观的得到了解:

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

  • 相关阅读:
    [APM] OneAPM 云监控部署与试用体验
    Elastic Stack 安装
    xBIM 综合使用案例与 ASP.NET MVC 集成(一)
    JQuery DataTables Selected Row
    力导向图Demo
    WPF ViewModelLocator
    Syncfusion SfDataGrid 导出Excel
    HTML Table to Json
    .net core 2.0 虚拟目录下载 Android Apk 等文件
    在BootStrap的modal中使用Select2
  • 原文地址:https://www.cnblogs.com/waw/p/2157016.html
Copyright © 2011-2022 走看看