Cómo analizar una cadena de consulta en una NameValueCollection en .NET


186

Me gustaría analizar una cadena como p1=6&p2=7&p3=8en un NameValueCollection.

¿Cuál es la forma más elegante de hacer esto cuando no tienes acceso al Page.Requestobjeto?

Respuestas:


356

Hay una utilidad .NET incorporada para esto: HttpUtility.ParseQueryString

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

Es posible que deba reemplazar querystringcon new Uri(fullUrl).Query.


26
Omar, no me funcionó en ASP.NET 4, me devolvió una clave de " stackoverflow.com?para " en lugar de "para". Así que estoy usando HttpUtility.ParseQueryString (nuevo Uri (fullUrl) .Query) que funciona correctamente para mí.
Michael

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

55
ParseQueryString es realmente una mala idea para usar en una aplicación de escritorio, porque no está incluida en el Perfil del Cliente; ¿Por qué instalar 100 M de bibliotecas adicionales en la computadora cliente para usar un método simple? Sin embargo, parece que Microsoft no tiene una mejor idea. La única forma es implementar un método propio o usar una implementación de código abierto.
Vitalii

2
VASoftOnline: en ese caso, puede usar la implementación Mono de ParseQueryString: github.com/mono/mono/blob/master/mcs/class/System.Web/… la licencia para eso es MIT X11: github.com/mono/mono / blob / master / LICENCIA
sw.

3
HttpUtility.ParseQueryStringsería mi recomendación, excepto que en el caso de que HttpUtility.ParseQueryString("&X=1&X=2&X=3")el resultado sea ....X=1,2,3...tener múltiples parámetros del mismo nombre es poco común pero necesario para admitir parámetros de controlador como int [], IEnumerable <int>, etc. (dichos parámetros podrían utilizarse para admitir varias casillas de verificación) consulte "Múltiples ocurrencias de la misma variable de cadena de consulta se consolidan en una entrada" según el sitio de MS . Una versión artesanal del método podría ser su única opción
dunxz

43

HttpUtility.ParseQueryString funcionará mientras esté en una aplicación web o no le importe incluir una dependencia en System.Web. Otra forma de hacer esto es:

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

55
debe verificar si las partes. Longitud> 1, para asegurarse de que puede llamar a las partes [1]
Alexandru Pupsa

2
¿Qué pasa si no hay valor? Por ejemplo, una cadena de consulta puede verse ?foo=1&bar. HttpUtilitylo analizaría como{ key = null, value = "bar" }
Thomas Levesque

Esto es excelente en comparación con HttpUtility.ParseQueryString porque no decodifica los valores (por lo que se conservan los valores codificados en base64)
CRice

1
En realidad, aún debe permitir que el valor '=', por ejemplo & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = se elimine el último carácter '='. Reescribí parte de su código para obtener el primer índice de '=' y la subcadena de la clave y el valor para arreglar esto (en lugar de usar la división).
CRice

28

Muchas de las respuestas proporcionan ejemplos personalizados debido a la dependencia de la respuesta aceptada en System.Web . Desde el paquete Microsoft.AspNet.WebApi.Client NuGet hay un método UriExtensions.ParseQueryString , que también se puede usar:

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

Entonces, si desea evitar la dependencia de System.Web y no quiere usar la suya propia, esta es una buena opción.


3
La misma función existe como una extensión en el espacio de nombres System.Net.Http (vea mi respuesta a continuación), no necesita otra dependencia completa ...
jvenema

@jvenema Desde dónde agrega la dependencia System.Net.Http.Formatting, creo que solo se proporciona agregando el paquete NuGet Microsoft.AspNet.WebApi.Client.
James Skimming

19

Quería eliminar la dependencia de System.Web para poder analizar la cadena de consulta de una implementación de ClickOnce, al tiempo que los requisitos previos se limitaban al "Subconjunto de marcos solo para clientes".

Me gustó la respuesta de rp. Agregué algo de lógica adicional.

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

Esto es realmente útil para Windows Phone, solo tiene que reemplazar el "NameValueCollection" con un "SortedDictionnary <string, string>"
Mike Bryant

44
Tenga cuidado al cambiar NameValueCollection por un diccionario: ¡no son lo mismo! Las cadenas de consulta admiten varias claves con el mismo valor, y también lo hace NameValueCollection.
Matt DeKrey

7

Necesitaba una función que sea un poco más versátil que la que ya se proporcionaba al trabajar con consultas OLSC.

  • Los valores pueden contener múltiples signos iguales
  • Decodificar caracteres codificados en nombre y valor
  • Capaz de ejecutarse en Client Framework
  • Capaz de ejecutarse en Mobile Framework.

Aquí está mi solución:

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

Puede que no sea una mala idea <Extension()>agregar eso también para agregar la capacidad a Uri.


7

Para hacerlo sin System.Web, sin escribirlo usted mismo, y sin paquetes NuGet adicionales:

  1. Agregar una referencia a System.Net.Http.Formatting
  2. Añadir using System.Net.Http;
  3. Usa este código:

    new Uri(uri).ParseQueryString()

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


3
Desde dónde está agregando la dependencia System.Net.Http.Formatting, creo que solo se proporciona agregando el paquete Microsoft.AspNet.WebApi.Client NuGet.
James Skimming

Huh, mi mal. Supongo que vino con el marco MVC que se instala automáticamente, por lo que no tuve que agregar ningún paquete adicional (Archivos de programa (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatting.dll)
jvenema

System.Net.Formatting EXTENSION VS2019 es una lista o pestaña separada de las referencias del marco tradicional
Sql Surfer

3

Si desea evitar la dependencia de System.Web que se requiere para usar HttpUtility.ParseQueryString , puede usar el Urimétodo de extensión que se ParseQueryStringencuentra en System.Net.Http.

Asegúrese de agregar una referencia (si aún no lo ha hecho) a System.Net.Httpsu proyecto.

Tenga en cuenta que debe convertir el cuerpo de la respuesta a válido Uripara que ParseQueryString(in System.Net.Http) funcione.

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 coloca las referencias de extensión separadas de las referencias de framework tradicionales.
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 ] );    
            }    
        }
    }

55
también se permite el punto y coma como separador de parámetros en http, mejor no reinventar la rueda
Matthew Lock

2

Me acabo de dar cuenta de que Web API Client tiene un ParseQueryStringmétodo de extensión que funciona en Uriay devuelve un HttpValueCollection:

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

1

Simplemente acceda a Request.QueryString. AllKeys mencionado como otra respuesta solo te da una variedad de claves.


1

HttpUtility.ParseQueryString(Request.Url.Query)return es HttpValueCollection(clase interna). Hereda 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

Dado que todo el mundo parece estar pegando su solución ... aquí está la mía :-) Necesitaba esto desde una biblioteca de clase sin System.Webobtener los parámetros de identificación de los hipervínculos almacenados.

Pensé en compartir porque encuentro esta solución más rápida y mejor.

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 este método: una cadena de consulta puede tener más de un valor para un parámetro dado. En este caso, su método arrojará un error de clave duplicada.
Thomas Levesque

Sí, al menos use una NameValueCollection, las cadenas de consulta con claves duplicadas son perfectamente legales.
Chad Grant

Además, su diccionario distingue entre mayúsculas y minúsculas, por lo que X = 1 yx = 1 serían claves diferentes. Necesita un nuevo diccionario <string, string> (StringComparer.OrdinalIgnoreCase);
Chad Grant

0

Acceda a Request.QueryString.Keys para una NameValueCollection de todos los parámetros de cadena de consulta.


0

Para obtener todos los valores de Querystring intente esto:

    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

Traduzco a la versión 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

Este es mi código, creo que es muy útil:

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;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.