Я знаю, что могу это сделать
var nv = HttpUtility.ParseQueryString(req.RawUrl);
Но есть ли способ конвертировать это обратно в URL?
var newUrl = HttpUtility.Something("/page", nv);
Я знаю, что могу это сделать
var nv = HttpUtility.ParseQueryString(req.RawUrl);
Но есть ли способ конвертировать это обратно в URL?
var newUrl = HttpUtility.Something("/page", nv);
Просто вызов ToString()
в NameValueCollection
вернет пары значений имени в формате name1=value1&name2=value2
querystring ready. Обратите внимание, что типы NameValueCollection
на самом деле не поддерживают это, и это вводит в заблуждение, чтобы предложить это, но поведение здесь работает из-за возвращаемого внутреннего типа, как описано ниже.
Спасибо @mjwills за указание, что метод HttpUtility.ParseQueryString
фактически возвращает внутренний HttpValueCollection
объект, а не обычный NameValueCollection
(несмотря на документацию указав NameValueCollection
). HttpValueCollection
автоматически кодирует запрос при использовании ToString()
, поэтому нет необходимости писать процедуру, которая проходит через коллекцию и использует метод UrlEncode
. Желаемый результат уже возвращен.
В результате в результате вы можете добавить его к URL-адресу и перенаправить:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
В настоящее время единственным способом использования HttpValueCollection
является использование метода ParseQueryString
, показанного выше (за исключением отражения, конечно). Похоже, что это не изменится, так как Подключить проблему, требующую опубликования этого класса, был закрыт со статусом "не исправить". "
В стороне вы можете вызвать методы Add
, Set
и Remove
на nameValues
, чтобы изменить любой элемент запроса, прежде чем добавлять его. Если вам интересно, что см. Мой ответ на другой вопрос.
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
Сделайте метод расширения, который использует пару циклов. Я предпочитаю это решение, потому что оно читаемо (без linq), не требует System.Web.HttpUtility и обрабатывает дубликаты ключей.
public static string ToQueryString(this NameValueCollection nvc)
{
if (nvc == null) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string key in nvc.Keys)
{
if (string.IsNullOrWhiteSpace(key)) continue;
string[] values = nvc.GetValues(key);
if (values == null) continue;
foreach (string value in values)
{
sb.Append(sb.Length == 0 ? "?" : "&");
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
}
}
return sb.ToString();
}
var queryParams = new NameValueCollection()
{
{ "order_id", "0000" },
{ "item_id", "1111" },
{ "item_id", "2222" },
{ null, "skip entry with null key" },
{ "needs escaping", "special chars ? = &" },
{ "skip entry with null value", null }
};
Console.WriteLine(queryParams.ToQueryString());
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
Это должно работать без слишком большого кода:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
Идея состоит в том, чтобы использовать HttpUtility.ParseQueryString
для генерации пустой коллекции типа HttpValueCollection
. Этот класс является подклассом NameValueCollection
, который помечен как internal
, так что ваш код не может легко создать его экземпляр.
Хорошая вещь о HttpValueCollection
состоит в том, что метод ToString
заботится о кодировке для вас. Используя метод NameValueCollection.Add(NameValueCollection)
, вы можете добавить существующие параметры строки запроса к вновь созданному объекту без необходимости сначала преобразовывать коллекцию Request.QueryString
в строку с кодировкой URL, а затем анализировать ее обратно в коллекцию.
Этот метод также может быть представлен как метод расширения:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
Собственно, вы также должны кодировать ключ, а не только значение.
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
Короткий ответ - использовать .ToString()
на NameValueCollection
и объединить его с исходным URL.
Однако я хотел бы указать несколько вещей:
Вы не можете использовать HttpUtility.ParseQueryString
на Request.RawUrl
. Метод ParseQueryString()
ищет такое значение: ?var=value&var2=value2
.
Если вы хотите получить NameValueCollection
параметров QueryString
, просто используйте Request.QueryString()
.
var nv = Request.QueryString;
Чтобы перестроить URL-адрес, просто используйте nv.ToString().
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
Если вы пытаетесь проанализировать строку url вместо использования объекта Request
, используйте Uri
и метод HttpUtility.ParseQueryString
.
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
Поскольку NameValueCollection
может иметь несколько значений для одного и того же ключа, если вы интересуетесь форматом запроса (поскольку он будет возвращен как значения, разделенные запятыми, а не "нотация массива" ), вы можете рассмотреть следующее.
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
Включите: key1=val1&key2[]=val2&empty&key2[]=val2b
, а не key1=val1&key2=val2,val2b&empty
.
string qs = string.Join("&",
// "loop" the keys
nvc.AllKeys.SelectMany(k => {
// "loop" the values
var values = nvc.GetValues(k);
if(values == null) return new[]{ k };
return nvc.GetValues(k).Select( (v,i) =>
// 'gracefully' handle formatting
// when there 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(v), i)
);
})
);
или если вам не нравится Linq так много...
string qs = nvc.ToQueryString(); // using...
public static class UrlExtensions {
public static string ToQueryString(this NameValueCollection nvc) {
return string.Join("&", nvc.GetUrlList());
}
public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
foreach(var k in nvc.AllKeys) {
var values = nvc.GetValues(k);
if(values == null) { yield return k; continue; }
for(int i = 0; i < values.Length; i++) {
yield return
// 'gracefully' handle formatting
// when there 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(values[i]), i);
}
}
}
}
Как уже отмечалось в комментариях, за исключением этого ответа, большинство других ответов относятся к сценарию (Request.QueryString
- это HttpValueCollection
, "не" a NameValueCollection
), а не буквальный вопрос.
Обновление: адресное значение нулевого значения из комментария.
Будет ли это работать для вас?
public static string BuildUrl(string relativeUrl, params string[] queryString)
{
// build queryString from string parameters
char[] trimChars = { ' ', '&', '?' };
StringBuilder builder = new StringBuilder();
string sepChar = "&";
string sep = String.Empty;
foreach (string q in queryString)
{
builder.Append(sep).Append(q.Trim(trimChars));
sep = sepChar;
}
if (String.IsNullOrEmpty(builder.ToString())) { return relativeUrl; }
else { return relativeUrl + "?" + builder.ToString(); }
}
Использование:
string url = BuildUrl("/mypage.apsx", "qs1=a", "qs2=b", "qs3=c");
В AspNet Core 2.0 вы можете использовать QueryHelpers метод AddQueryString.
Вы можете использовать.
var ur = new Uri("/page",UriKind.Relative);
если этот nv имеет строку типа, которую вы можете добавить к первому параметру uri. Как
var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);
Я всегда использую UriBuilder для преобразования URL-адреса с повторением запроса в действительный и правильно закодированный URL-адрес.
var url = "http://my-link.com?foo=bar";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");
uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();
// http://my-link.com:80/?foo=bar&yep=foo%26bar
Как предложил @Atchitutchuk, вы можете использовать QueryHelpers.AddQueryString в ASP.NET Core:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}