在MVC的ActionLink中出现RouteValueDictionary/对象问题

4

所以这里是:

我有一个 HTML 助手,它用当前 URL 的可选参数呈现 ActionLink。 这个 HTML 助手还允许您按照自己的意愿添加一些更多的可选参数,并将它们合并在一个 RouteValueDictionary 中。

    public static string ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller, object extraRVs, object htmlAttributes) {

        //get current optional params from current URL
        NameValueCollection c = helper.ViewContext.RequestContext.HttpContext.Request.QueryString;

        //put those in a dict
        RouteValueDictionary r = new RouteValueDictionary();
        foreach (string s in c.AllKeys) {
            r.Add(s, c[s]);
        }

        RouteValueDictionary htmlAtts = new RouteValueDictionary(htmlAttributes);

        RouteValueDictionary extra = new RouteValueDictionary(extraRVs);

        //merge them
        RouteValueDictionary m = RouteValues.MergeRouteValues(r, extra);

        return helper.ActionLink(linktext, action, controller, m, htmlAtts).ToHtmlString();
    }

这个很好用,但我现在添加了SecurityAware Actionlinks。
所以
        return helper.ActionLink(linktext, action, controller, m, htmlAtts).ToHtmlString();

成为

        return helper.SecurityTrimmedActionLink(linktext, action, controller, m, htmlAtts);

然后调用:

   public static string SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, object extraRVs, object htmlAttributes) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, extraRVs, htmlAttributes, false);
    }

    public static string SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, object extraRVs, object htmlAttributes, bool showDisabled) {
        if (controller == null) {
            RouteData routeData = htmlHelper.ViewContext.RouteData;
            controller = routeData.GetRequiredString("controller");
        }
        if (IsAccessibleToUser(action, controller)) {
            return htmlHelper.ActionLink(linkText, action, controller, extraRVs, htmlAttributes).ToHtmlString();
        } else {
            return showDisabled ? String.Format("<span>{0}</span>", linkText) : "";
        }
    }

现在这样是不行的。虽然编译通过了,但我的URL看起来不太好。
   <a count="3" keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" href="/2011-2012/Instelling?Count=3&amp;Keys=System.Collections.Generic.Dictionary%602%2BKeyCollection%5BSystem.String%2CSystem.Object%5D&amp;Values=System.Collections.Generic.Dictionary%602%2BValueCollection%5BSystem.String%2CSystem.Object%5D">Back to List</a>

正如你所见,以前可以运行的代码现在无法运行,因为它将RouteValueDictionary作为对象处理,这给我带来了不想要的结果。

所以我想,如果我再次将它们变成RouteValueDictionary呢。

       if (IsAccessibleToUser(action, controller)) {

            RouteValueDictionary parsedextraRVs = null;
            if (extraRVs != null && extraRVs.GetType().Name == "RouteValueDictionary") {
                parsedextraRVs = (RouteValueDictionary)extraRVs;
            }

            RouteValueDictionary parsedHtmlAttributes = null;
            if (htmlAttributes != null && htmlAttributes.GetType().Name == "RouteValueDictionary") {
                parsedHtmlAttributes = (RouteValueDictionary)htmlAttributes;
            }


            return htmlHelper.ActionLink(linkText, action, controller, parsedextraRVs == null ? extraRVs : parsedextraRVs, parsedHtmlAttributes == null ? htmlAttributes : parsedHtmlAttributes).ToHtmlString();
        }

但这也给了我刚才发布的URL。为什么我的ActionLinkwParams方法可以使用,但当ActionLinkwParams调用SecurityTrimmedActionLink方法时却不行呢?我该如何解决?
2个回答

7

SecurityTrimmedActionLink方法的签名修改为如下:

public static string SecurityTrimmedActionLink(
    this HtmlHelper htmlHelper, 
    string linkText, 
    string action, 
    string controller, 
    RouteValueDictionary extraRVs, 
    RouteValueDictionary htmlAttributes
)

请注意这个这个之间的区别。在您的情况下(不起作用的情况),您调用了接受对象的第二个重载,但在您的情况下,您没有传递匿名对象,而是将RouteValueDictionary视为匿名对象,并将其公共属性(Count、Keys、Values)序列化为属性。
备注:您的助手方法不正确。它们返回字符串。这不是应该的方式。助手方法应该返回MvcHtmlString
因此,代替
public static string ActionLinkwParams(...)
{
    ...
    return helper.ActionLink(linktext, action, controller, m, htmlAtts).ToHtmlString();
}

应该是这样的:

public static MvcHtmlString ActionLinkwParams(...)
{
    ...
    return helper.ActionLink(linktext, action, controller, m, htmlAtts);
}

我不能这样做,因为有时我直接调用SecurityTrimmedActionLink,在这种情况下,我会以new{id=something}的形式发送对象。 - Stefanvds
@Stefanvd,在你的第一个例子中,你调用了这个:http://msdn.microsoft.com/en-us/library/dd504988.aspx。你看到它需要RouteValueDictionary吗?在你的第二个例子中,你调用了一个带有object的方法,所以你需要传递一个匿名对象,比如`new { foo = "bar" },它应该输出foo="bar"属性,但是你却传递了一个RouteValueDictionary,它输出Keys="3" Values="..."`。 - Darin Dimitrov
但为什么当我将这两个“对象”解析为“RouteValueDictionary”时,它为什么不调用此方法http://msdn.microsoft.com/en-us/library/dd504988.aspx? - Stefanvds
@Stefanvds,它没有被调用是因为你在SecurityTrimmedActionLink方法签名中将最后一个参数定义为object类型的变量,这是编译器解析的重载。当你在该方法上按F12时,你会发现VS会导航到错误的方法。 - Darin Dimitrov
所以我需要以不同的方式修复它 :) 我仍然需要能够使用匿名类型和路由值调用此方法。我想我需要在我的SecurityTrimmedActionLink上进行重载。 - Stefanvds
显示剩余2条评论

0

所以最终我做的是(感谢Darin)增加了一些额外的重载来使其工作。

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, null, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, object extraRVs) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, null, extraRVs, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, object extraRVs) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, extraRVs, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, RouteValueDictionary extraRVs) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, null, extraRVs, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, RouteValueDictionary extraRVs) {
        return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, extraRVs, null);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, object extraRVs, object htmlAttributes) {

        RouteValueDictionary rv = new RouteValueDictionary(extraRVs);
        RouteValueDictionary html = new RouteValueDictionary(htmlAttributes);

        return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, extraRVs, html);
    }

    public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, RouteValueDictionary extraRVs, IDictionary<String, Object> htmlAttributes) {
        if (controller == null) {
            RouteData routeData = htmlHelper.ViewContext.RouteData;
            controller = routeData.GetRequiredString("controller");
        }
        if (IsAccessibleToUser(action, controller)) {
            return htmlHelper.ActionLink(linkText, action, controller, extraRVs, htmlAttributes);
        } else {
            return MvcHtmlString.Empty;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接