Как оставить параметры URL неэкранированными в ASP.NET MVC? - PullRequest
7 голосов
/ 05 февраля 2009

Я заметил, что параметр URL returnurl в ссылках входа / выхода из Stackoverflow не экранируется, но когда я пытаюсь добавить путь в качестве параметра к маршруту, он экранируется.

Итак / login? Returnurl = / questions / ask show / login? Returnurl =% 2fquestions% 2fask, и это уродливо. Как мне получить его, чтобы он не экранировал возвращаемое значение?

Вот что я делаю в коде:

Html.ActionLink("Login", "Login", "Account", new { returnurl=Request.Path }, null)

Ответы [ 5 ]

7 голосов
/ 05 февраля 2009

Как я могу получить это, чтобы не избежать возвращаемое значение

Как насчет этого?

var url = Url.Action("Login", "Account", new {returnurl = Request.Path});
var unEncodedUrl = HttpUtility.UrlDecode(url);
Response.Write("<a href='" + unEncodedUrl + "'>...</a>");

Убедитесь, что именно этого вы и хотите, URL-кодирование имеет свое назначение.

1 голос
/ 05 февраля 2009

Параметр не без экранирования. Вы заметите URL:

http://stackoverflow.com/users/login?returnurl=%2fquestions%2fask

действительно работает - SO читает и удаляет этот параметр как обычно. Если вы хотите включить в параметр другие недопустимые символы, такие как '&', вам все равно придется их экранировать.

Хитрость в том, что символ '/', в частности, не обязательно должен быть экранирован на% в параметрах запроса. Он должен быть экранирован в других контекстах, таких как часть пути, поэтому URLEncode всегда кодирует его, чтобы быть в безопасности.

Если вы просто хотите, чтобы URL выглядел красивее, просто экранируйте параметр как обычно (что вы должны сделать, чтобы экранировать все остальные символы, которые должны обрабатываться правильно), а затем выполните замену строки в '% 2f' на ' /'.

1 голос
/ 05 февраля 2009

Я понимаю один из комментариев о кодировании, происходящем по определенной причине; это будет только исключением, а не правилом.

Вот что я собрал, как это можно улучшить?

    public static string ActionLinkNoEscape(this HtmlHelper html, string linkText, string actionName, string controllerName, object values, object htmlAttributes)
    {
        RouteValueDictionary routeValues = new RouteValueDictionary(values);
        RouteValueDictionary htmlValues = new RouteValueDictionary(htmlAttributes);

        UrlHelper urlHelper = new UrlHelper(html.ViewContext.RequestContext, RouteTable.Routes);
        string url = urlHelper.Action(actionName, controllerName);
        url += "?";
        List<string> paramList = new List<string>();
        foreach (KeyValuePair<string, object> pair in routeValues)
        {
            object value = pair.Value ?? "";
            paramList.Add(String.Concat(pair.Key, "=", Convert.ToString(value, CultureInfo.InvariantCulture)));
        }
        url += String.Join("&", paramList.ToArray());

        TagBuilder builder = new TagBuilder("a");
        builder.InnerHtml = string.IsNullOrEmpty(linkText) ? "" : HttpUtility.HtmlEncode(linkText);
        builder.MergeAttributes<string, object>(htmlValues);
        builder.MergeAttribute("href", url);
        return builder.ToString(TagRenderMode.Normal);
    }
0 голосов
/ 05 февраля 2009

Я не верю, что есть способ обойти это, встроенный в фреймворк. Фактическое построение URL-адреса происходит в методе System.Web.Routing.ParsedRoute.Bind, и нет никаких условий, используемых для предотвращения выхода.

Похоже, что метод расширения - это путь, но он несколько более надежен, чем упомянутый ранее.

0 голосов
/ 05 февраля 2009

Моим решением аналогичной проблемы было написать собственное расширение. Покопавшись в коде, я не смог найти способ сделать это иначе. Ваш может выглядеть так.

public static class HtmlHelperExtensions
{
    public static string LoginLinkWithReturnUrl( this HtmlHelper helper,
                                                 string linkText,
                                                 string action,
                                                 string controller,
                                                 string returnUrl,
                                                 object htmlAttributes )
    {
         TagBuilder builder = new TagBuilder("a");
         builder.Attributes.Add( "href",
                                  string.Format( "/{0}/{1}?returnurl={2}",
                                                 controller,
                                                 action,
                                                 returnUrl ) );
         var attrDict = new RouteValueDictionary( htmlAttributes );
         builder.MergeAttributes( attrDict );
         builder.InnerHtml = linkText;
         return builder.ToString();
    }
}

Я думаю, что у меня возникла та же проблема при создании и использовании UrlHelper, поэтому я использовал механизм string.Format. YMMV.

...