Pergunta

Eu gostaria de analisar uma string como p1=6&p2=7&p3=8 dentro de NameValueCollection.

Qual é a maneira mais elegante de fazer isso quando você não tem acesso ao Page.Request objeto?

Foi útil?

Solução

Existe um utilitário .NET integrado para isso: HttpUtility.ParseQueryString

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

Você pode precisar substituir querystring com new Uri(fullUrl).Query.

Outras dicas

HttpUtility.ParseQueryString funcionará contanto que você esteja em um aplicativo da web ou não se importe em incluir uma dependência do System.Web.Outra maneira de fazer isso é:

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

Muitas das respostas fornecem exemplos personalizados devido à dependência da resposta aceita em Sistema.Web.De Microsoft.AspNet.WebApi.Client Pacote NuGet, há um UriExtensions.ParseQueryString, método que também pode ser usado:

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

Então, se você quiser evitar o Sistema.Web dependência e não quer criar o seu próprio, esta é uma boa opção.

Eu queria remover a dependência de System.Web para poder analisar a string de consulta de uma implantação ClickOnce, tendo os pré-requisitos limitados ao "Subconjunto de estrutura somente cliente".

Gostei da resposta do rp.Eu adicionei alguma 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;
    }

Eu precisava de uma função que fosse um pouco mais versátil do que a que já era fornecida ao trabalhar com consultas OLSC.

  • Os valores podem conter vários sinais de igual
  • Decodifique caracteres codificados em nome e valor
  • Capaz de rodar no Client Framework
  • Capaz de rodar em Mobile Framework.

Aqui está minha solução:

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

Pode não ser uma má ideia abordar <Extension()> nisso também para adicionar a capacidade ao próprio Uri.

Para fazer isso sem System.Web, sem escrever você mesmo e sem pacotes NuGet adicionais:

  1. Adicione uma referência a System.Net.Http.Formatting
  2. Adicionar using System.Net.Http;
  3. Use este código:

    new Uri(uri).ParseQueryString()
    

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

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

Acabei de perceber isso Cliente de API Web tem um ParseQueryString método de extensão que funciona em um Uri e retorna um HttpValueCollection:

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

Se você quiser evitar a dependência do System.Web necessária para usar HttpUtility.ParseQueryString, você poderia usar o Uri método de extensão ParseQueryString encontrado em System.Net.Http.

Certifique-se de adicionar uma referência (se ainda não o fez) a System.Net.Http no seu projecto.

Observe que você deve converter o corpo da resposta em um válido Uri para que ParseQueryString (em System.Net.Http)funciona.

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

Basta acessar Request.QueryString.AllKeys mencionado como outra resposta apenas fornece uma série de chaves.

HttpUtility.ParseQueryString(Request.Url.Query) retorno é HttpValueCollection (classe interna).Ele herda 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); 

Se você não deseja a dependência System.Web, basta colar este código-fonte da classe HttpUtility.

Acabei de juntar isso a partir do código-fonte de Mono.Ele contém o HttpUtility e todas as suas dependências (como IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Então usar HttpUtility.ParseQueryString.

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

Já que todo mundo parece estar colando sua solução.Aqui está o meu :-) eu precisava disso de dentro de uma biblioteca de classes sem System.Web para buscar parâmetros de id de hiperlinks armazenados.

Pensei em compartilhar porque acho essa solução mais rápida e mais bonita.

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")

Clique em Request.QueryString.Keys para obter um NameValueCollection de todos os parâmetros da string de consulta.

Para obter todos os valores de Querystring, tente isto:

    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
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());

Eu traduzo para a versão C# de Josh-brown em 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;
}

Este é o meu código, acho que é muito ú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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top