Comment analyser une chaîne de requête dans un NameValueCollection dans .NET


186

Je voudrais analyser une chaîne comme p1=6&p2=7&p3=8dans un fichier NameValueCollection.

Quelle est la manière la plus élégante de faire cela lorsque vous n'avez pas accès à l' Page.Requestobjet?

Réponses:


356

Il existe un utilitaire .NET intégré pour cela: HttpUtility.ParseQueryString

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

Vous devrez peut-être remplacer querystringpar new Uri(fullUrl).Query.


26
Omar, cela n'a pas fonctionné pour moi sur ASP.NET 4, il a renvoyé une clé de " stackoverflow.com?para " au lieu de "para". J'utilise donc HttpUtility.ParseQueryString (new Uri (fullUrl) .Query) qui fonctionne correctement pour moi.
Michael

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

5
ParseQueryString est vraiment une mauvaise idée à utiliser dans une application de bureau, car il n'est pas inclus dans le profil client; pourquoi installer 100 M de bibliothèques supplémentaires sur l'ordinateur client pour n'utiliser qu'une seule méthode simple? Cependant, il semble que Microsoft n'a pas de meilleure idée. Le seul moyen est d'implémenter sa propre méthode ou d'utiliser une implémentation open source.
Vitalii

2
VASoftOnline: Dans ce cas, vous pouvez utiliser l'implémentation Mono de ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web / ... la licence pour cela est MIT X11: github.com/mono/mono / blob / master / LICENCE
sw.

3
HttpUtility.ParseQueryStringserait ma recommandation sauf que dans le cas du HttpUtility.ParseQueryString("&X=1&X=2&X=3")résultat, ....X=1,2,3...avoir plusieurs paramètres du même nom est rare mais nécessaire pour prendre en charge les paramètres du contrôleur tels que int [], IEnumerable <int>, etc. (ces paramètres peuvent être utilisés pour prendre en charge plusieurs cases à cocher) voir "Plusieurs occurrences de la même variable de chaîne de requête sont consolidées dans une seule entrée" selon le site MS . Une version artisanale de la méthode pourrait être votre seule option
dunxz

43

HttpUtility.ParseQueryString fonctionnera tant que vous êtes dans une application Web ou que cela ne vous dérange pas d'inclure une dépendance sur System.Web. Une autre façon de procéder est:

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
vous devriez vérifier si parts.Length> 1, pour être sûr que vous pouvez appeler des pièces [1]
Alexandru Pupsa

2
Et s'il n'y a aucune valeur? par exemple, une chaîne de requête peut ressembler à ?foo=1&bar. HttpUtilityl'analyserait comme{ key = null, value = "bar" }
Thomas Levesque

C'est génial par rapport à HttpUtility.ParseQueryString car il ne décode pas les valeurs (donc les valeurs encodées en base64 sont conservées)
CRice

1
En fait, vous devez toujours autoriser la valeur '=' par exemple & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = aura le dernier caractère '=' supprimé. J'ai réécrit une partie de votre code pour obtenir le premier index de '=' et une sous-chaîne de la clé et de la valeur pour résoudre ce problème (au lieu d'utiliser split).
CRice

28

Un grand nombre de réponses fournissent des exemples personnalisés en raison de la dépendance de la réponse acceptée à System.Web . À partir du package NuGet Microsoft.AspNet.WebApi.Client , il existe une méthode UriExtensions.ParseQueryString , qui peut également être utilisée:

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

Donc, si vous voulez éviter la dépendance System.Web et que vous ne voulez pas rouler vous-même, c'est une bonne option.


3
La même fonction existe en tant qu'extension dans l'espace de noms System.Net.Http (voir ma réponse ci-dessous), pas besoin d'une autre dépendance entière ...
jvenema

@jvenema D'où ajoutez-vous la dépendance System.Net.Http.Formatting, je crois qu'elle n'est fournie qu'en ajoutant le package NuGet Microsoft.AspNet.WebApi.Client.
James Skimming

19

Je voulais supprimer la dépendance sur System.Web afin que je puisse analyser la chaîne de requête d'un déploiement ClickOnce, tout en ayant les prérequis limités au "Sous-ensemble de cadre client uniquement".

J'ai aimé la réponse de RP. J'ai ajouté une logique supplémentaire.

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

ceci est vraiment utile pour Windows Phone, il vous suffit de remplacer le "NameValueCollection" par un "SortedDictionnary <string, string>"
Mike Bryant

4
Soyez prudent lorsque vous remplacez NameValueCollection par un dictionnaire - ils ne sont pas les mêmes! Les chaînes de requête prennent en charge plusieurs clés avec la même valeur, tout comme NameValueCollection.
Matt DeKrey

7

J'avais besoin d'une fonction un peu plus polyvalente que ce qui était déjà fourni lors de l'utilisation de requêtes OLSC.

  • Les valeurs peuvent contenir plusieurs signes égaux
  • Décoder les caractères encodés dans le nom et la valeur
  • Capable de s'exécuter sur Client Framework
  • Capable de fonctionner sur Mobile Framework.

Voici ma solution:

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

Ce n'est peut-être pas une mauvaise idée de s'attaquer <Extension()>à cela aussi pour ajouter la capacité à Uri lui-même.


7

Pour ce faire sans System.Web, sans l'écrire vous-même et sans packages NuGet supplémentaires:

  1. Ajouter une référence à System.Net.Http.Formatting
  2. Ajouter using System.Net.Http;
  3. Utilisez ce code:

    new Uri(uri).ParseQueryString()

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


3
D'où ajoutez-vous la dépendance System.Net.Http.Formatting, je pense qu'elle n'est fournie qu'en ajoutant le package NuGet Microsoft.AspNet.WebApi.Client.
James Skimming

Huh, mon mal. Je suppose qu'il est venu avec le framework MVC qui est installé automatiquement, donc je n'ai pas eu à ajouter de packages supplémentaires (Program Files (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll)
jvenema

System.Net.Formatting EXTENSION VS2019 est une liste ou un onglet séparé des références de framework traditionnelles
Sql Surfer

3

Si vous souhaitez éviter la dépendance à System.Web requise pour utiliser HttpUtility.ParseQueryString , vous pouvez utiliser la Uriméthode d'extension ParseQueryStringtrouvée dans System.Net.Http.

Assurez-vous d'ajouter une référence (si vous ne l'avez pas déjà fait) à System.Net.Httpdans votre projet.

Notez que vous devez convertir le corps de la réponse en un fichier valide Uripour que ParseQueryString(in System.Net.Http) fonctionne.

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 sépare les références d'extension des références de framework traditionnelles.
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
le point-virgule est également autorisé comme séparateur de paramètres dans http, mieux vaut ne pas réinventer la roue
Matthew Lock

2

Je viens de réaliser que Web API Client a une ParseQueryStringméthode d'extension qui fonctionne sur a Uriet retourne a HttpValueCollection:

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

1

Accédez simplement à Request.QueryString. AllKeys mentionné comme une autre réponse vous donne juste un tableau de clés.


1

HttpUtility.ParseQueryString(Request.Url.Query)return est HttpValueCollection(classe interne). Il hérite de 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

Si vous ne voulez pas la dépendance System.Web, collez simplement ce code source de la classe HttpUtility.

Je viens de fouetter cela à partir du code source de Mono . Il contient le HttpUtility et toutes ses dépendances (comme IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Ensuite, utilisez HttpUtility.ParseQueryString.

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


1

Puisque tout le monde semble coller sa solution ... voici la mienne :-) J'en avais besoin depuis une bibliothèque de classes sans System.Webrécupérer les paramètres d'id à partir des hyperliens stockés.

Je pensais partager parce que je trouve cette solution plus rapide et plus esthétique.

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

Usage:

Statics.QueryGet(url, "id")

1
Juste un problème avec cette méthode: une chaîne de requête peut avoir plus d'une valeur pour un paramètre donné. Dans ce cas, votre méthode lèvera une erreur de clé en double.
Thomas Levesque

oui, utilisez au moins un NameValueCollection, les chaînes de requêtes avec des clés en double sont parfaitement légales.
Chad Grant

De plus, votre dictionnaire est sensible à la casse, donc X = 1 et x = 1 seraient des clés différentes. Besoin d'un nouveau dictionnaire <string, string> (StringComparer.OrdinalIgnoreCase);
Chad Grant

0

Accédez à Request.QueryString.Keys pour un NameValueCollection de tous les paramètres de chaîne de requête.


0

Pour obtenir toutes les valeurs Querystring, essayez ceci:

    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

Je traduis en version C # de josh-brown en 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

C'est mon code, je pense que c'est très 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;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.