Jak parsować ciąg zapytania w NameValueCollection w .NET


186

Chciałbym parsować ciąg taki jak p1=6&p2=7&p3=8na NameValueCollection.

Jaki jest najbardziej elegancki sposób, gdy nie masz dostępu do Page.Requestobiektu?

Odpowiedzi:


356

Do tego celu służy wbudowane narzędzie .NET: HttpUtility.ParseQueryString

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

Być może trzeba wymienić querystringz new Uri(fullUrl).Query.


26
Omar, nie działało to dla mnie na ASP.NET 4, zwróciło klucz „ stackoverflow.com?para ” zamiast „para”. Więc używam HttpUtility.ParseQueryString (nowy Uri (fullUrl) .Query), który działa poprawnie dla mnie.
Michael

2
qscoll [„p1”], qscoll [„p2”] i qscoll [„p3”]
SMUsamaShah

5
ParseQueryString jest naprawdę kiepskim pomysłem do użycia w aplikacji komputerowej, ponieważ nie jest uwzględniony w profilu klienta; po co instalować 100 mln dodatkowych bibliotek na komputerze klienckim, aby użyć tylko jednej prostej metody? Wygląda jednak na to, że Microsoft nie ma lepszego pomysłu. Jedynym sposobem jest wdrożenie własnej metody lub użycie implementacji typu open source.
Vitalii

2
VASoftOnline: W takim przypadku możesz użyć implementacji Mono ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web/... licencja na to MIT X11: github.com/mono/mono / blob / master / LICENCJA
sw.

3
HttpUtility.ParseQueryStringbyłoby moją rekomendacją, z wyjątkiem tego, że w przypadku HttpUtility.ParseQueryString("&X=1&X=2&X=3")wyniku jest to, że ....X=1,2,3...posiadanie wielu parametrów o tej samej nazwie jest rzadkie, ale potrzebne do obsługi parametrów kontrolera, takich jak int [], IEnumerable <int> itp. (takich parametrów można użyć do obsługi wielu pól wyboru) patrz „Wiele wystąpień tej samej zmiennej ciągu zapytania jest skonsolidowanych w jednym wpisie” zgodnie z witryną MS . Ręcznie przygotowana wersja metody może być twoją jedyną opcją
dunxz

43

HttpUtility.ParseQueryString będzie działać tak długo, jak jesteś w aplikacji internetowej, lub nie przeszkadza ci to zależność od System.Web. Innym sposobem na to jest:

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

5
należy sprawdzić, czy części. Długość> 1, aby mieć pewność, że można wywołać części [1]
Alexandru Pupsa

2
Co jeśli nie ma wartości? np. może wyglądać ciąg zapytania ?foo=1&bar. HttpUtilityparsowałby to jako{ key = null, value = "bar" }
Thomas Levesque,

Jest to świetne w porównaniu do HttpUtility.ParseQueryString, ponieważ nie dekoduje wartości (więc wartości zakodowane w base64 są zachowane)
CRice

1
W rzeczywistości nadal musisz zezwolić na wartość „=” na przykład & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = spowoduje usunięcie ostatniego znaku „=”. Przepisałem część kodu, aby uzyskać pierwszy indeks „=” i podciągnąć klucz i wartość, aby to naprawić (zamiast używania podziału).
CRice

28

Wiele odpowiedzi zawiera niestandardowe przykłady z powodu zależności zaakceptowanej odpowiedzi od System.Web . Z pakietu Microsoft.AspNet.WebApi.Client NuGet dostępna jest metoda UriExtensions.ParseQueryString , której można również użyć:

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

Więc jeśli chcesz uniknąć zależności System.Web i nie chcesz tworzyć własnych, jest to dobra opcja.


3
Ta sama funkcja istnieje jako rozszerzenie w przestrzeni nazw System.Net.Http (patrz moja odpowiedź poniżej), nie ma potrzeby kolejnej całej zależności ...
jvenema 24.10.2015

@jvenema Skąd dodajesz zależność System.Net.Http.Formatting, uważam, że jest ona zapewniona tylko przez dodanie pakietu Microsoft.AspNet.WebApi.Client NuGet.
James Skimming

19

Chciałem usunąć zależność od System.Web, aby móc przeanalizować ciąg zapytania wdrożenia ClickOnce, mając jednocześnie wymagania wstępne ograniczone do „podzbioru środowiska tylko dla klienta”.

Podobała mi się odpowiedź RP. Dodałem dodatkową logikę.

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;
    }

jest to naprawdę pomocne dla Windows Phone, wystarczy zastąpić „NameValueCollection” na „SortedDictionnary <string, string>”
Mike Bryant

4
Zachowaj ostrożność podczas przełączania NameValueCollection dla Dictionary - to nie to samo! Ciągi zapytań obsługują wiele kluczy o tej samej wartości, podobnie jak NameValueCollection.
Matt DeKrey

7

Potrzebowałem funkcji, która jest nieco bardziej uniwersalna niż ta, która była już dostępna podczas pracy z zapytaniami OLSC.

  • Wartości mogą zawierać wiele znaków równości
  • Dekoduj zakodowane znaki zarówno w nazwie, jak i wartości
  • Może działać w Client Framework
  • Może działać na Mobile Framework.

Oto moje rozwiązanie:

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

Być może nie jest to zły pomysł <Extension()>, aby dodać to samo, aby dodać zdolność do samego Uri.


7

Aby to zrobić bez System.Web, bez samodzielnego pisania i bez dodatkowych pakietów NuGet:

  1. Dodaj odniesienie do System.Net.Http.Formatting
  2. Dodaj using System.Net.Http;
  3. Użyj tego kodu:

    new Uri(uri).ParseQueryString()

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


3
Skąd dodajesz zależność System.Net.Http.Formatting, uważam, że jest ona udostępniana tylko poprzez dodanie pakietu Microsoft.AspNet.WebApi.Client NuGet.
James Skimming

Huh, mój zły. Wydaje mi się, że przyszedł ze automatycznie instalowanym frameworkiem MVC, więc nie musiałem dodawać żadnych pakietów add'l (Program Files (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll)
jvenema

System.Net.Formatting EXTENSION VS2019 to osobna lista lub karta z tradycyjnych odniesień do ram
Sql Surfer

3

Jeśli chcesz uniknąć zależności od System.Web, która jest wymagana do użycia HttpUtility.ParseQueryString , możesz użyć Urimetody rozszerzenia ParseQueryStringznalezionej w System.Net.Http.

Pamiętaj, aby dodać odniesienie (jeśli jeszcze tego nie zrobiłeś) do System.Net.Httpswojego projektu.

Pamiętaj, że musisz przekonwertować treść odpowiedzi na poprawną Uri, aby ParseQueryString(in System.Net.Http) działała.

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

System.Net.Formatting EXTENSION VS2019 oddziela odniesienia do rozszerzeń od tradycyjnych odniesień do ram.
Sql Surfer,

2
    private void button1_Click( object sender, EventArgs e )
    {
        string s = @"p1=6&p2=7&p3=8";
        NameValueCollection nvc = new NameValueCollection();

        foreach ( string vp in Regex.Split( s, "&" ) )
        {
            string[] singlePair = Regex.Split( vp, "=" );
            if ( singlePair.Length == 2 )
            {
                nvc.Add( singlePair[ 0 ], singlePair[ 1 ] );    
            }    
        }
    }

5
średnik jest również dozwolony jako separator parametrów w http, lepiej nie wymyślać koła ponownie
Matthew Lock

2

Właśnie zdałem sobie sprawę, że klient Web API ma ParseQueryStringmetodę rozszerzenia, która działa na a Urii zwraca HttpValueCollection:

var parameters = uri.ParseQueryString();
string foo = parameters["foo"];

1

Wystarczy uzyskać dostęp do Request.QueryString. AllKeys wymienione jako kolejna odpowiedź po prostu daje ci zestaw kluczy.


1

HttpUtility.ParseQueryString(Request.Url.Query)return is HttpValueCollection(klasa wewnętrzna). Dziedziczy po 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); 


1

Ponieważ wszyscy wydają się wklejać swoje rozwiązanie .. oto moje :-) Potrzebowałem tego z biblioteki klasowej bez System.Webpobierania parametrów id z przechowywanych hiperłączy.

Myślałem, że podzielę się, ponieważ uważam to rozwiązanie za szybsze i lepiej wyglądające.

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];
    }
}

Stosowanie:

Statics.QueryGet(url, "id")

1
Tylko jeden problem z tą metodą: ciąg zapytania może mieć więcej niż jedną wartość dla danego parametru. W takim przypadku metoda zgłosi błąd klucza duplikatu.
Thomas Levesque,

tak, przynajmniej użyj NameValueCollection, kwerendy ze zduplikowanymi kluczami są całkowicie legalne.
Chad Grant,

Ponadto w słowniku rozróżniana jest wielkość liter, więc X = 1 i x = 1 będą różnymi kluczami. Potrzebujesz nowego słownika <ciąg, ciąg> (StringComparer.OrdinalIgnoreCase);
Chad Grant

0

Hit Request.QueryString.Keys dla NameValueCollection wszystkich parametrów ciągu zapytania.


0

Aby uzyskać wszystkie wartości Querystring, spróbuj:

    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

0
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());

0
let search = window.location.search;

console.log(search);

let qString = search.substring(1);

while(qString.indexOf("+") !== -1)

   qString  = qString.replace("+", "");

let qArray = qString.split("&");

let values = [];

for(let i = 0; i < qArray.length; i++){
   let pos = qArray[i].search("=");
   let keyVal = qArray[i].substring(0, pos);
   let dataVal = qArray[i].substring(pos + 1);
   dataVal = decodeURIComponent(dataVal);
   values[keyVal] = dataVal;
}

-1

Tłumaczę na josh-brown w wersji C # w 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;
}

-2

To jest mój kod, myślę, że jest bardzo przydatny:

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;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.