Come analizzare una stringa di query in NameValueCollection in .NET


186

Vorrei analizzare una stringa come p1=6&p2=7&p3=8in a NameValueCollection.

Qual è il modo più elegante per farlo quando non hai accesso Page.Requestall'oggetto?

Risposte:


356

Esiste un'utilità .NET integrata per questo: HttpUtility.ParseQueryString

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

Potrebbe essere necessario sostituirlo querystringcon new Uri(fullUrl).Query.


26
Omar, non ha funzionato per me su ASP.NET 4, ha restituito una chiave di " stackoverflow.com?para " anziché "para". Quindi sto usando HttpUtility.ParseQueryString (new Uri (fullUrl) .Query) che funziona correttamente per me.
Michael,

2
qscoll ["p1"], qscoll ["p2"] e qscoll ["p3"]
SMUsamaShah

5
ParseQueryString è una pessima idea da usare nell'applicazione desktop, perché non è inclusa nel profilo client; perché installare 100 M di librerie aggiuntive sul computer client per usare solo un metodo semplice? Tuttavia, sembra che Microsoft non abbia idea migliore. L'unico modo è implementare il proprio metodo o utilizzare l'implementazione open source.
Vitalii,

2
VASoftOnline: in tal caso è possibile utilizzare l'implementazione Mono di ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web/… la licenza è MIT X11: github.com/mono/mono / blob / master / LICENSE
sw.

3
HttpUtility.ParseQueryStringsarebbe la mia raccomandazione, tranne che nel caso in cui HttpUtility.ParseQueryString("&X=1&X=2&X=3")il risultato sia ....X=1,2,3...Avere più parametri con lo stesso nome è raro ma necessario per supportare parametri del controller come int [], IEnumerable <int> ecc (tali parametri potrebbero essere usati per supportare più caselle di controllo) vedere "Le ricorrenze multiple della stessa variabile della stringa di query sono consolidate in una voce" come per sito MS . Una versione artigianale del metodo potrebbe essere la tua unica opzione
dunxz,

43

HttpUtility.ParseQueryString funzionerà fino a quando ti trovi in ​​un'app Web o non ti dispiace includere una dipendenza da System.Web. Un altro modo per farlo è:

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
è necessario verificare se parti.Lunghezza> 1, per essere sicuri di poter chiamare parti [1]
Alexandru Pupsa,

2
E se non ci fosse valore? ad esempio, può apparire una stringa di query ?foo=1&bar. HttpUtilitylo analizzerebbe come{ key = null, value = "bar" }
Thomas Levesque il

Questo è fantastico rispetto a HttpUtility.ParseQueryString perché non decodifica i valori (quindi i valori codificati in base64 vengono conservati)
CRice

1
In realtà, è comunque necessario consentire il valore '=', ad esempio & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = rimarrà l'ultimo carattere '='. Ho riscritto parte del tuo codice per ottenere il primo indice di '=' e sottostringa la chiave e il valore per risolvere questo problema (invece di usare split).
CRice

28

Molte risposte forniscono esempi personalizzati a causa della dipendenza della risposta accettata da System.Web . Dal pacchetto NuGet Microsoft.AspNet.WebApi.Client c'è un UriExtensions.ParseQueryString , metodo che può anche essere usato:

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

Quindi, se vuoi evitare la dipendenza System.Web e non vuoi farne una tua, questa è una buona opzione.


3
La stessa funzione esiste come estensione nello spazio dei nomi System.Net.Http (vedi la mia risposta di seguito), non c'è bisogno di un'altra dipendenza completa ...
jvenema

@jvenema Da dove stai aggiungendo la dipendenza System.Net.Http.Formatting, credo che sia fornita solo aggiungendo il pacchetto NuGet Microsoft.AspNet.WebApi.Client.
James Skimming,

19

Volevo rimuovere la dipendenza da System.Web in modo da poter analizzare la stringa di query di una distribuzione ClickOnce, pur avendo i prerequisiti limitati al "Sottoinsieme framework solo client".

Mi è piaciuta la risposta di rp. Ho aggiunto qualche logica aggiuntiva.

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

questo è davvero utile per Windows Phone, devi solo sostituire "NameValueCollection" con un "SortedDictionnary <stringa, stringa>"
Mike Bryant

4
Fai attenzione quando cambi NameValueCollection per un Dizionario - non sono gli stessi! Le stringhe di query supportano più chiavi con lo stesso valore, così come NameValueCollection.
Matt DeKrey

7

Avevo bisogno di una funzione un po 'più versatile di quella già fornita quando si lavorava con le query OLSC.

  • I valori possono contenere più segni di uguale
  • Decodifica i caratteri codificati sia nel nome che nel valore
  • In grado di funzionare su Client Framework
  • Capace di funzionare su Mobile Framework.

Ecco la mia soluzione:

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

Potrebbe non essere una cattiva idea puntare anche <Extension()>su questo per aggiungere la capacità a Uri stesso.


7

Per fare ciò senza System.Web, senza scriverlo tu stesso e senza pacchetti NuGet aggiuntivi:

  1. Aggiungi un riferimento a System.Net.Http.Formatting
  2. Inserisci using System.Net.Http;
  3. Usa questo codice:

    new Uri(uri).ParseQueryString()

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


3
Da dove stai aggiungendo la dipendenza System.Net.Http.Formatting, credo che sia fornito solo aggiungendo il pacchetto NuGet Microsoft.AspNet.WebApi.Client.
James Skimming,

Eh, mio ​​cattivo. Immagino che sia arrivato con il framework MVC installato automaticamente, quindi non ho dovuto aggiungere alcun pacchetto aggiuntivo (Programmi (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll)
jvenema il

System.Net.Formatting EXTENSION VS2019 è un elenco o una scheda separata dai riferimenti del framework tradizionale
Sql Surfer

3

Se si desidera evitare la dipendenza da System.Web richiesta per utilizzare HttpUtility.ParseQueryString , è possibile utilizzare il Urimetodo di estensione ParseQueryStringtrovato in System.Net.Http.

Assicurati di aggiungere un riferimento (se non l'hai già fatto) al System.Net.Httptuo progetto.

Si noti che è necessario convertire il corpo della risposta in un valido in Urimodo che ParseQueryString(in System.Net.Http) funzioni.

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 mette i riferimenti di estensione separati dai riferimenti di framework tradizionali.
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
il punto e virgola è anche consentito come separatore di parametri in http, meglio non reinventare la ruota
Matthew Lock,

2

Ho appena realizzato che il client API Web ha un ParseQueryStringmetodo di estensione che funziona su un Urie restituisce un HttpValueCollection:

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

1

Accedi a Request.QueryString. AllKeys menzionato come un'altra risposta ti dà solo una serie di chiavi.


1

HttpUtility.ParseQueryString(Request.Url.Query)il ritorno è HttpValueCollection(classe interna). Eredita da 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

Se non si desidera la dipendenza System.Web, è sufficiente incollare questo codice sorgente dalla classe HttpUtility.

Ho appena montato questo insieme dal codice sorgente di Mono . Contiene HttpUtility e tutte le sue dipendenze (come IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Quindi utilizzare HttpUtility.ParseQueryString.

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


1

Dal momento che tutti sembrano incollare la sua soluzione .. ecco la mia :-) Ne avevo bisogno all'interno di una libreria di classi senza System.Webrecuperare i parametri ID dai collegamenti ipertestuali memorizzati.

Ho pensato di condividere perché trovo questa soluzione più veloce e più bella.

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

Uso:

Statics.QueryGet(url, "id")

1
Solo un problema con questo metodo: una stringa di query può avere più di un valore per un dato parametro. In questo caso, il metodo genererà un errore chiave duplicato.
Thomas Levesque,

sì, almeno usa un NameValueCollection, le stringhe di query con chiavi duplicate sono perfettamente legali.
Chad Grant,

Inoltre, il tuo dizionario fa distinzione tra maiuscole e minuscole, quindi X = 1 e x = 1 sarebbero chiavi diverse. È necessario un nuovo dizionario <string, string> (StringComparer.OrdinalIgnoreCase);
Chad Grant,

0

Hit Request.QueryString.Keys per un NameValueCollection di tutti i parametri della stringa di query.


0

Per ottenere tutti i valori Querystring prova questo:

    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

Traduco in versione C # di josh-brown in 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

Questo è il mio codice, penso che sia molto utile:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.