NameValueCollection to URL Query? - PullRequest
       21

NameValueCollection to URL Query?

66 голосов
/ 05 октября 2010

Я знаю, что могу сделать это

var nv = HttpUtility.ParseQueryString(req.RawUrl);

Но есть ли способ преобразовать это обратно в URL?

Ответы [ 11 ]

101 голосов
/ 05 октября 2010

Простой вызов ToString() на NameValueCollection вернет пары имя-значение в формате name1=value1&name2=value2. Обратите внимание, что 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, показанный выше (конечно, кроме отражения). Похоже, что это не изменится, так как проблема Connect, требующая обнародования этого класса, была закрыта со статусом «не будет исправлено».

Кроме того, вы можете вызвать методы Add, Set и Remove для nameValues, чтобы изменить любой из элементов строки запроса перед его добавлением. Если вы заинтересованы в этом , посмотрите мой ответ на другой вопрос .

62 голосов
/ 27 октября 2013
string q = String.Join("&",
             nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
13 голосов
/ 15 сентября 2016

Создайте метод расширения, который использует пару циклов.Я предпочитаю это решение, потому что оно доступно для чтения (без 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
12 голосов
/ 13 июля 2017

Это должно работать без слишком большого кода:

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();
}
5 голосов
/ 31 января 2016

На самом деле, вы должны также кодировать ключ, а не только значение.

string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
3 голосов
/ 09 декабря 2014

Поскольку 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's 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)
        );
    })
);

или, если вы неМне так нравится Линк ...

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's 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, "not" a NameValueCollection), а не буквальным вопросом.

Обновление: устранена проблема с нулевым значением из комментария.

3 голосов
/ 05 октября 2010

Короткий ответ - использовать .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());
1 голос
/ 05 декабря 2017

В AspNet Core 2.0 вы можете использовать QueryHelpers Метод AddQueryString.

1 голос
/ 05 октября 2010

Будет ли это работать для вас?

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");
0 голосов
/ 28 июня 2016

Я всегда использую 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
...