繁体   English   中英

添加到htmlAttributes以获取自定义ActionLink帮助程序扩展

[英]Add to htmlAttributes for custom ActionLink helper extension

我正在尝试创建一个Html.ActionLink(...)HtmlHelper的简单自定义版本

我想为传入的htmlAttributes匿名对象附加一组额外的属性。

public static MvcHtmlString NoFollowActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
    var customAttributes = new RouteValueDictionary(htmlAttributes) {{"rel", "nofollow"}};
    var link = htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, customAttributes);
    return link;
}

所以在我看来我会这样:

@Html.NoFollowActionLink("Link Text", "MyAction", "MyController")

我希望能够呈现如下链接:

<a href="/MyController/MyAction" rel="nofollow">Link Text</a>

但相反,我得到:

<a href="/MyController/MyAction" values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" count="1">Link Text</a>

我已经尝试了将匿名类型转换为RouteValueDictionary的各种方法,添加到它然后将其传递到根ActionLink(...)方法或转换为Dictionary,或使用HtmlHelper.AnonymousObjectToHtmlAttributes并执行相同但似乎没有工作。

您得到的结果是由此源代码引起的:

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
    return ActionLink(htmlHelper, linkText, actionName, controllerName, TypeHelper.ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}

正如您所见, HtmlHelper.AnonymousObjectToHtmlAttributes在里面被调用。 这就是为什么在传递RouteValueDictionary对象时获取valueskeys的原因。

只有两种方法匹配您的参数列表:

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)

第二个重载对你的参数没有任何作用,只是传递它们。 您需要修改代码以调用其他重载:

public static MvcHtmlString NoFollowActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues = null, object htmlAttributes = null)
{
    var routeValuesDict = new RouteValueDictionary(routeValues);

    var customAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    if (!customAttributes.ContainsKey("rel"))
        customAttributes.Add("rel", "nofollow");

    return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValuesDict, customAttributes);
}

当您将routeValues作为RouteValueDictionary传递routeValuesRouteValueDictionary选择另一个重载( RouteValueDictionary正在实现IDictionary<string, object>所以它很好),并且返回的链接是正确的。

如果rel属性已经存在于htmlAttributes对象中,则会抛出异常:

System.ArgumentException: An item with the same key has already been added.

当您想要更新收到的htmlAttributes对象以便添加新属性(rel)时,您需要将匿名htmlAttributes对象转换为IDictionary<string,object> (因为您无法向匿名对象添加新属性)。

这意味着您需要调用ActionLink方法的这个重载 ,这也需要将匿名routeValues转换为RouteValueDictionary

您可以使用new RouteValueDictionary(routeValues)轻松转换路径值。 要转换html属性,您需要一些反射逻辑,例如在此问题中 (正如slawek在他的回答中已经提到的,你也可以利用RouteValueDictionary已经实现了一个字典并以相同的方式转换htmlAttributes)

最后你的扩展将是这样的:

public static MvcHtmlString NoFollowActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues = null, object htmlAttributes = null)
{
    var htmlAttributesDictionary = new Dictionary<string, object>();
    if (htmlAttributes != null)
    {
        foreach (var prop in htmlAttributes.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            htmlAttributesDictionary.Add(prop.Name, prop.GetValue(htmlAttributes, null));
        }
    }
    htmlAttributesDictionary["rel"] = "nofollow";

    var routeValuesDictionary = new RouteValueDictionary(routeValues);

    var link = htmlHelper.ActionLink(linkText, actionName, controllerName, routeValuesDictionary, htmlAttributesDictionary);
    return link;
}

如果你这样称呼它:

@Html.NoFollowActionLink("Link Text", "MyAction", "MyController", new { urlParam="param1" }, new { foo = "dummy" })

您将获得以下html:

<a foo="dummy" href="/MyController/MyAction?urlParam=param1" rel="nofollow">Link Text</a>

注意,因为在将原始属性添加到字典中之后添加/更新rel属性,即使调用者为属性指定了另一个值,它也总是强制rel="nofollow"

希望能帮助到你!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM