Как разобрать строку запроса в NameValueCollection в .NET

Я хотел бы разобрать строку, например p1=6&p2=7&p3=8, на NameValueCollection.

Каков самый элегантный способ сделать это, когда у вас нет доступа к объекту Page.Request?


person Nathan Smith    schedule 16.09.2008    source источник


Ответы (17)


Для этого есть встроенная утилита .NET: HttpUtility.ParseQueryString

// C#
NameValueCollection qscoll = HttpUtility.ParseQueryString(querystring);
' VB.NET
Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

Возможно, вам потребуется заменить querystring на new Uri(fullUrl).Query.

person Guy Starbuck    schedule 16.09.2008
comment
Омар, у меня это не сработало на ASP.NET 4, он вернул ключ stackoverflow.com?para вместо пункта. Итак, я использую HttpUtility.ParseQueryString (новый Uri (fullUrl) .Query), который у меня правильно работает. - person Michael; 06.04.2011
comment
qscoll [p1], qscoll [p2] и qscoll [p3] - person SMUsamaShah; 02.09.2011
comment
ParseQueryString - действительно плохая идея для использования в настольных приложениях, потому что он не включен в профиль клиента; зачем устанавливать 100 M дополнительных библиотек на клиентском компьютере, чтобы использовать один простой метод? Однако похоже, что у Microsoft нет лучшего представления. Единственный способ - реализовать собственный метод или использовать реализацию с открытым исходным кодом. - person Vitalii; 01.06.2012
comment
VASoftOnline: в этом случае вы можете использовать Mono-реализацию ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web/ лицензией для этого является MIT X11: github.com/mono/mono/blob/master/LICENSE - person sw.; 04.01.2013
comment
@ Майкл +1. HttpUtility.ParseQueryString(new Uri(fullUrl).Query) - очень важная информация. Может быть, это не должно быть только в комментариях. - person fiberOptics; 27.08.2014
comment
HttpUtility.ParseQueryString была бы моей рекомендацией, за исключением того, что в случае HttpUtility.ParseQueryString("&X=1&X=2&X=3") результатом будет ....X=1,2,3... Наличие нескольких параметров с одним и тем же именем является редкостью, но необходимо для поддержки таких параметров контроллера, как int [], IEnumerable ‹int› и т. Д. (Такие параметры могут использоваться для поддержки несколько флажков) см. Несколько экземпляров одной и той же переменной строки запроса объединены в одну запись согласно сайт MS. Созданная вручную версия метода может быть вашим единственным вариантом. - person dunxz; 15.06.2016
comment
@Vitaliy Хотя я согласен с тем, что для этого глупо использовать всю библиотеку System.Web, в этом методе происходит гораздо больше, чем просто анализ URL-адреса, включая множество вызовов кода, который существует только в System.Web . Скорее всего, вы могли бы получить исходный код и построить собственную реализацию, но это нетривиально. - person Trevor Hart; 11.12.2017
comment
Если значение параметра имеет '&', то этот метод не работает должным образом. например? x1 = 123 & X2 = 23 & test, тогда он извлечет 3 параметра! - person SeeSharp; 05.10.2018
comment
Комментарий Azure 2018 - Полная платформа .Net CORE - Если вы избегаете ссылок на System.Web, вам будут полезны приведенные ниже ответы от Дж. Венемы и А. Санчеса. - person Sql Surfer; 08.12.2018

HttpUtility.ParseQueryString будет работать, пока вы находитесь в веб-приложении или не возражаете против включения зависимости от System.Web. Другой способ сделать это:

NameValueCollection queryParameters = new NameValueCollection();
string[] querySegments = queryString.Split('&');
foreach(string segment in querySegments)
{
   string[] parts = segment.Split('=');
   if (parts.Length > 0)
   {
      string key = parts[0].Trim(new char[] { '?', ' ' });
      string val = parts[1].Trim();

      queryParameters.Add(key, val);
   }
}
person Scott Dorman    schedule 16.09.2008
comment
вы должны проверить, есть ли детали. Длина ›1, чтобы убедиться, что вы можете вызвать детали [1] - person Alexandru Pupsa; 29.09.2015
comment
Что делать, если нет ценности? например строка запроса может выглядеть как ?foo=1&bar. HttpUtility проанализирует это как { key = null, value = "bar" } - person Thomas Levesque; 20.09.2016
comment
Это здорово по сравнению с HttpUtility.ParseQueryString, потому что он не декодирует значения (поэтому значения в кодировке base64 сохраняются) - person CRice; 07.07.2017
comment
Фактически, вам все равно нужно разрешить значение '=', например, & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = будет удален последний символ '='. Я переписал часть вашего кода, чтобы получить первый индекс '=', и подставил ключ и значение, чтобы исправить это (вместо использования разделения). - person CRice; 07.07.2017
comment
Есть еще много угловых случаев, которые здесь не рассматриваются. - person Bogdan Gavril MSFT; 02.10.2020

Многие ответы содержат настраиваемые примеры из-за зависимости принятого ответа от системы .Web. В пакете NuGet Microsoft.AspNet.WebApi.Client есть UriExtensions.ParseQueryString, метод, который также может использоваться:

var uri = new Uri("https://stackoverflow.com/a/22167748?p1=6&p2=7&p3=8");
NameValueCollection query = uri.ParseQueryString();

Итак, если вы хотите избежать зависимости System.Web и не Не хочу кататься самостоятельно, это хороший вариант.

person James Skimming    schedule 04.03.2014
comment
Та же функция существует как расширение в пространстве имен System.Net.Http (см. Мой ответ ниже), нет необходимости в другой полной зависимости ... - person jvenema; 24.10.2015
comment
@jvenema Откуда вы добавляете зависимость System.Net.Http.Formatting, я считаю, что она предоставляется только путем добавления пакета NuGet Microsoft.AspNet.WebApi.Client. - person James Skimming; 11.11.2015
comment
немного безумие, что нужно добавить совершенно новый пакет nuget в качестве зависимости, особенно тот, в имени которого есть AspNet, который пахнет только предназначенным для развертывания на сервере (в моем случае мне это нужно для мобильного / настольного компьютера Приложение Xamarin ...) - person knocte; 10.08.2020

Я хотел удалить зависимость от System.Web, чтобы я мог анализировать строку запроса развертывания ClickOnce, имея при этом предварительные требования, ограниченные «Подмножеством только клиентской инфраструктуры».

Мне понравился ответ rp. Я добавил дополнительную логику.

public static NameValueCollection ParseQueryString(string s)
    {
        NameValueCollection nvc = new NameValueCollection();

        // remove anything other than query string from url
        if(s.Contains("?"))
        {
            s = s.Substring(s.IndexOf('?') + 1);
        }

        foreach (string vp in Regex.Split(s, "&"))
        {
            string[] singlePair = Regex.Split(vp, "=");
            if (singlePair.Length == 2)
            {
                nvc.Add(singlePair[0], singlePair[1]);
            }
            else
            {
                // only one key with no value specified in query string
                nvc.Add(singlePair[0], string.Empty);
            }
        }

        return nvc;
    }
person densom    schedule 24.08.2009
comment
это действительно полезно для Windows Phone, вам просто нужно заменить NameValueCollection строкой SortedDictionnary ‹, строка› - person Mike Bryant; 14.11.2013
comment
Будьте осторожны при переключении NameValueCollection для словаря - это не одно и то же! Строки запроса поддерживают несколько ключей с одним и тем же значением, как и NameValueCollection. - person Matt DeKrey; 08.05.2014

Мне нужна была функция, которая была бы немного более универсальной, чем то, что уже было предоставлено при работе с запросами OLSC.

  • Значения могут содержать несколько знаков равенства
  • Расшифровать закодированные символы как в имени, так и в значении
  • Возможность работы на Client Framework
  • Возможность работы на Mobile Framework.

Вот мое решение:

Public Shared Function ParseQueryString(ByVal uri As Uri) As System.Collections.Specialized.NameValueCollection
    Dim result = New System.Collections.Specialized.NameValueCollection(4)
    Dim query = uri.Query
    If Not String.IsNullOrEmpty(query) Then
        Dim pairs = query.Substring(1).Split("&"c)
        For Each pair In pairs
            Dim parts = pair.Split({"="c}, 2)

            Dim name = System.Uri.UnescapeDataString(parts(0))
            Dim value = If(parts.Length = 1, String.Empty,
                System.Uri.UnescapeDataString(parts(1)))

            result.Add(name, value)
        Next
    End If
    Return result
End Function

Возможно, неплохо было бы добавить <Extension()> и к самому Uri.

person Josh Brown    schedule 15.05.2013

Чтобы сделать это без System.Web, без написания самостоятельно и без дополнительных пакетов NuGet:

  1. Добавить ссылку на System.Net.Http.Formatting
  2. Добавить using System.Net.Http;
  3. Используйте этот код:

    new Uri(uri).ParseQueryString()
    

https://msdn.microsoft.com/en-us/library/system.net.http.uriextensions(v=vs.118).aspx

person jvenema    schedule 19.10.2015
comment
Откуда вы добавляете зависимость System.Net.Http.Formatting, я считаю, что она предоставляется только путем добавления пакета NuGet Microsoft.AspNet.WebApi.Client. - person James Skimming; 11.11.2015
comment
Ха, у меня плохо. Я предполагаю, что он поставляется с автоматически установленной платформой MVC, поэтому мне не пришлось добавлять какие-либо пакеты add'l (Program Files (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll) - person jvenema; 22.06.2016
comment
System.Net.Formatting EXTENSION VS2019 - это отдельный список или вкладка из традиционных ссылок на фреймворк. - person Sql Surfer; 08.12.2018

Если вы хотите избежать зависимости от System.Web, необходимой для использования HttpUtility. ParseQueryString, вы можете использовать Uri метод расширения ParseQueryString из System.Net.Http.

Обязательно добавьте ссылку (если вы еще этого не сделали) на System.Net.Http в свой проект.

Обратите внимание, что вам нужно преобразовать тело ответа в действительный Uri, чтобы ParseQueryStringSystem.Net.Http) работал.

string body = "value1=randomvalue1&value2=randomValue2";

// "http://localhost/query?" is added to the string "body" in order to create a valid Uri.
string urlBody = "http://localhost/query?" + body;
NameValueCollection coll = new Uri(urlBody).ParseQueryString();
person Amadeus Sánchez    schedule 16.08.2017
comment
System.Net.Formatting EXTENSION VS2019 помещает ссылки на расширения отдельно от традиционных ссылок на фреймворк. - person Sql Surfer; 08.12.2018

Я только что понял, что Web API Client имеет ParseQueryString метод расширения, который работает на Uri и возвращает HttpValueCollection:

var parameters = uri.ParseQueryString();
string foo = parameters["foo"];
person Thomas Levesque    schedule 23.07.2014

Если вам не нужна зависимость System.Web, просто вставьте этот исходный код из класса HttpUtility.

Я просто собрал это из исходного кода Mono. . Он содержит HttpUtility и все его зависимости (например, IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Затем используйте HttpUtility.ParseQueryString.

https://gist.github.com/bjorn-ali-goransson/b04a7c44808bb2de8cca3fc9a3762f9c

person Community    schedule 03.07.2016

Просто войдите в Request.QueryString. AllKeys, упомянутый в качестве еще одного ответа, просто дает вам массив ключей.

person Mike Becatti    schedule 16.09.2008

HttpUtility.ParseQueryString(Request.Url.Query) возврат HttpValueCollection (внутренний класс). Он наследуется от NameValueCollection.

    var qs = HttpUtility.ParseQueryString(Request.Url.Query);
    qs.Remove("foo"); 

    string url = "~/Default.aspx"; 
    if (qs.Count > 0)
       url = url + "?" + qs.ToString();

    Response.Redirect(url); 
person alex1kirch    schedule 17.11.2011

Поскольку каждый, кажется, вставляет свое решение ... вот мое :-) Мне это нужно из библиотеки классов без System.Web для получения параметров идентификатора из сохраненных гиперссылок.

Думал, что поделюсь, потому что нахожу это решение более быстрым и красивым.

public static class Statics
    public static Dictionary<string, string> QueryParse(string url)
    {
        Dictionary<string, string> qDict = new Dictionary<string, string>();
        foreach (string qPair in url.Substring(url.IndexOf('?') + 1).Split('&'))
        {
            string[] qVal = qPair.Split('=');
            qDict.Add(qVal[0], Uri.UnescapeDataString(qVal[1]));
        }
        return qDict;
    }

    public static string QueryGet(string url, string param)
    {
        var qDict = QueryParse(url);
        return qDict[param];
    }
}

Использование:

Statics.QueryGet(url, "id")
person Tiele Declercq    schedule 23.01.2014
comment
Только одна проблема с этим методом: строка запроса может иметь более одного значения для данного параметра. В этом случае ваш метод выдаст ошибку дублирования ключа. - person Thomas Levesque; 24.07.2014
comment
да, по крайней мере, используйте NameValueCollection, строки запроса с повторяющимися ключами совершенно законны. - person Chad Grant; 09.04.2017
comment
Кроме того, ваш словарь чувствителен к регистру, поэтому X = 1 и x = 1 будут разными ключами. Нужен новый словарь ‹строка, строка› (StringComparer.OrdinalIgnoreCase); - person Chad Grant; 09.04.2017

Нажмите Request.QueryString.Keys для NameValueCollection всех параметров строки запроса.

person Mark Glorie    schedule 16.09.2008

Чтобы получить все значения Querystring, попробуйте следующее:

    Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

Dim sb As New StringBuilder("<br />")
For Each s As String In qscoll.AllKeys

  Response.Write(s & " - " & qscoll(s) & "<br />")

Next s
person mirko cro 1234    schedule 24.02.2015

Я перевожу на C # версию josh-brown на VB

private System.Collections.Specialized.NameValueCollection ParseQueryString(Uri uri)
{
    var result = new System.Collections.Specialized.NameValueCollection(4);
    var query = uri.Query;
    if (!String.IsNullOrEmpty(query))
    {
        var pairs = query.Substring(1).Split("&".ToCharArray());
        foreach (var pair in pairs)
        {
            var parts = pair.Split("=".ToCharArray(), 2);
            var name = System.Uri.UnescapeDataString(parts[0]);
            var value = (parts.Length == 1) ? String.Empty : System.Uri.UnescapeDataString(parts[1]);
            result.Add(name, value);
        }
    }
    return result;
}
person elgoya    schedule 20.08.2016

Это мой код, я думаю, он очень полезен:

public String GetQueryString(string ItemToRemoveOrInsert = null, string InsertValue = null )
{
    System.Collections.Specialized.NameValueCollection filtered = new System.Collections.Specialized.NameValueCollection(Request.QueryString);
    if (ItemToRemoveOrInsert != null)
    {
        filtered.Remove(ItemToRemoveOrInsert);
        if (!string.IsNullOrWhiteSpace(InsertValue))
        {
            filtered.Add(ItemToRemoveOrInsert, InsertValue);
        }
    }

    string StrQr = string.Join("&", filtered.AllKeys.Select(key => key + "=" + filtered[key]).ToArray());
    if (!string.IsNullOrWhiteSpace(StrQr)){
        StrQr="?" + StrQr;
    }

    return StrQr;
}
person Farhawd    schedule 10.11.2013

person    schedule
comment
точка с запятой также разрешена в качестве разделителя параметров в http, лучше не изобретать велосипед - person Matthew Lock; 28.10.2009