Проблема RouteValueDictionary/объекта в mvc ActionLink

так вот оно:

У меня есть помощник html, который отображает ActionLinks с дополнительными параметрами текущего URL-адреса. этот помощник html также позволяет вам добавлять дополнительные необязательные параметры по своему усмотрению и объединяет их в 1 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.

so

        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>

как вы видите, то, что раньше работало, теперь не работает, потому что он принимает RouteValueDictionarys как объекты, что дает мне не тот результат, который я хочу.

поэтому я подумал, что, если я снова сделаю их RouteValueDictionarys.

       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? и как мне это исправить?


person Stefanvds    schedule 05.01.2011    source источник


Ответы (2)


Измените подпись метода SecurityTrimmedActionLink на это:

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

Обратите внимание на разницу между этим и это. В вашем случае (тот, который не работает) вы вызываете вторую перегрузку, принимающую объекты, но в вашем случае вы передаете не анонимные объекты, а RouteValueDictionary, который обрабатывается так, как если бы это был анонимный объект и его общедоступные свойства (Count, Ключи, значения) сериализуются как атрибуты.

Примечание. Ваши вспомогательные методы неверны. Они возвращают строки. Это не так, как должно быть. Вспомогательные методы должны возвращать 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);
}
person Darin Dimitrov    schedule 05.01.2011
comment
Я не могу этого сделать, потому что иногда я вызываю эту SecurityTrimmedActionLink напрямую, и в этом случае я отправляю объекты в виде new{id=something} - person Stefanvds; 05.01.2011
comment
@Stefanvds, вам придется это сделать, если вам нужны правильные атрибуты, или вам нужно будет сделать частный метод, а другой - общедоступным. - person Darin Dimitrov; 05.01.2011
comment
я знаю, что это из-за методов перегрузки Actionlink, но почему это работало в моей первой версии? я не могу заметить никакой разницы. у меня также были объекты в моем методе.... - person Stefanvds; 05.01.2011
comment
@Stefanvd, в вашем первом примере вы вызываете это: msdn.microsoft.com/ en-us/library/dd504988.aspx. Вы видите, что он принимает RouteValueDictionary? Во втором примере вы вызываете объект с объектом, поэтому вам нужно передать анонимный объект, например new { foo = "bar" }, который должен выводить атрибут foo="bar", но вместо этого вы передаете RouteValueDictionary, который выводит Keys="3" Values="...". - person Darin Dimitrov; 05.01.2011
comment
байт, почему он не вызывает этот метод msdn.microsoft.com/en-us/ library/dd504988.aspx, когда я анализирую оба «объекта» на «routevaluedictionary»? - person Stefanvds; 05.01.2011
comment
@Stefanvds, он не вызывает его, потому что вы передаете в качестве последнего аргумента переменную, тип которой определен как object в вашей подписи метода SecurityTrimmedActionLink, и это перегрузка, которая разрешается компилятором. Нажмите F12 над методом, и вы увидите, что VS перейдет к неправильному методу. - person Darin Dimitrov; 05.01.2011
comment
поэтому мне нужно исправить это по-другому :) мне все еще нужно иметь возможность вызывать этот метод с анонимными типами И со значениями маршрута. я думаю, мне нужна перегрузка моего SecurityTrimmedActionLink - person Stefanvds; 05.01.2011

Итак, что я сделал в конце (спасибо 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;
        }
    }
person Stefanvds    schedule 05.01.2011