ИмяValueCollection для URL-запроса?

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

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

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

var newUrl = HttpUtility.Something("/page", nv);

Ответ 1

Просто вызов 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, чтобы изменить любой элемент запроса, прежде чем добавлять его. Если вам интересно, что см. Мой ответ на другой вопрос.

Ответ 2

string q = String.Join("&",
             nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));

Ответ 3

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

Ответ 4

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

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

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

string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));

Ответ 6

Короткий ответ - использовать .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());

Ответ 7

Поскольку 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), а не буквальный вопрос.

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

Ответ 8

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

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");

Ответ 9

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

Ответ 10

Вы можете использовать.

var ur = new Uri("/page",UriKind.Relative);

если этот nv имеет строку типа, которую вы можете добавить к первому параметру uri. Как

var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);

Ответ 11

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

Ответ 12

Как предложил @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('?');
    }