Как оставить параметры URL неэкранированными в ASP.NET MVC?
-
21-08-2019 - |
Вопрос
Я заметил, что параметр URL returnurl в ссылках Stackoverflow login / logout не экранируется, но когда я пытаюсь добавить path в качестве параметра к маршруту, он экранируется.
Итак, /login?returnurl=/questions/ask показывает /login?returnurl=%2fquestions%2fask, и это как-то некрасиво.Как мне сделать так, чтобы значение returnurl не экранировалось?
Вот что я делаю в коде:
Html.ActionLink("Login", "Login", "Account", new { returnurl=Request.Path }, null)
Решение 2
Я понимаю, что один из комментариев о кодировании происходит по какой-то причине;это было бы всего лишь исключением, а не правилом.
Вот что я собрал воедино, как это можно улучшить?
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);
}
Другие советы
Как мне заставить его не экранировать значение returnurl
Как насчет этого?
var url = Url.Action("Login", "Account", new {returnurl = Request.Path});
var unEncodedUrl = HttpUtility.UrlDecode(url);
Response.Write("<a href='" + unEncodedUrl + "'>...</a>");
Но будь уверен, что это то, чего ты хочешь, Кодировка URL-адресов имеет свое назначение.
Этот параметр равен нет незамеченный.Вы заметите URL-адрес:
http://stackoverflow.com/users/login?returnurl=%2fquestions%2fask
действительно работает - КАК и чтение и отмена экранирования этого параметра в обычном режиме.Если бы вы хотели включить в параметр другие символы, выходящие за рамки, такие как '&', вам все равно пришлось бы экранировать их.
Хитрость заключается просто в том, что символ '/', в частности, не обязательно должен быть %-экранирован в параметрах запроса.IT делает должен быть экранирован в других контекстах, например, в части пути, поэтому URLEncode всегда кодирует его, чтобы быть в безопасности.
Если вы просто хотите, чтобы URL-адрес выглядел красивее, просто экранируйте параметр как обычно (что вы должны сделать, чтобы экранировать все остальные символы, которые должны обрабатываться правильно), а затем замените строку в '%2f' на '/'.
Моим решением аналогичной проблемы было написать свое собственное расширение.Покопавшись в коде, я не смог найти способа сделать это иначе.Ваш может выглядеть примерно так.
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.Вместо этого механизм форматирования.ИММВ.
Я не верю, что есть способ обойти это, который встроен в фреймворк.Фактическое построение URL-адреса происходит в System.Web.Routing.ParsedRoute.Метод Bind, и нет никаких условий, используемых для предотвращения экранирования.
Похоже, что можно использовать метод расширения, но он немного более надежный, чем тот, который упоминался ранее.