Obter parâmetros de URL de uma string no .NET


239

Eu tenho uma string no .NET que é realmente um URL. Eu quero uma maneira fácil de obter o valor de um parâmetro específico.

Normalmente, eu usaria apenas Request.Params["theThingIWant"], mas essa sequência não é da solicitação. Eu posso criar um novo Uriitem assim:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

Posso usar myUri.Querypara obter a string de consulta ... mas, aparentemente, tenho que encontrar uma maneira regular de dividi-la.

Estou sentindo falta de algo óbvio ou não existe uma maneira de fazer isso sem criar um tipo de regex etc.?

Respostas:


494

Use o ParseQueryStringmétodo estático da System.Web.HttpUtilityclasse que retorna NameValueCollection.

Uri myUri = new Uri("http://www.example.com?param1=good&param2=bad");
string param1 = HttpUtility.ParseQueryString(myUri.Query).Get("param1");

Verifique a documentação em http://msdn.microsoft.com/en-us/library/ms150046.aspx


14
Isso não parece detectar o primeiro parâmetro. por exemplo, a análise de " google.com/... ," não detectar o parâmetro q
Andrew Shepherd

@ Andrew confirmo. É estranho (bug?). Você ainda pode usar HttpUtility.ParseQueryString(myUri.Query).Get(0)e ele extrairá o primeiro parâmetro. `
Mariusz Pawelski

Alguma ferramenta .NET para criar um URL de consulta parametrizado?
Shimmy Weitzhandler

6
Você não pode analisar URLs de consulta completos com HttpUtility.ParseQueryString(string)! Como o próprio nome diz, é analisar Query Strings, não URLs com parâmetros de consulta. Se você quiser fazer isso, primeiro divida-o da ?seguinte forma: Url.Split('?')e obtenha o último elemento usando (dependendo da situação e do que você precisa) [0]ou LINQ's Last()/ LastOrDefault().
quer

1
Ao testar isso sozinho, a assinatura parece ter sido alterada para isso: HttpUtility.ParseQueryString (uri.Query) .GetValues ​​("param1"). Primeiro ()
O Senador

48

Provavelmente é isso que você quer

var uri = new Uri("http://domain.test/Default.aspx?var1=true&var2=test&var3=3");
var query = HttpUtility.ParseQueryString(uri.Query);

var var2 = query.Get("var2");

34

Aqui está outra alternativa se, por qualquer motivo, você não puder ou não quiser usar HttpUtility.ParseQueryString().

Isso é construído para ser um pouco tolerante a cadeias de consulta "malformadas", ou seja, http://test/test.html?empty=se torna um parâmetro com um valor vazio. O chamador pode verificar os parâmetros, se necessário.

public static class UriHelper
{
    public static Dictionary<string, string> DecodeQueryParameters(this Uri uri)
    {
        if (uri == null)
            throw new ArgumentNullException("uri");

        if (uri.Query.Length == 0)
            return new Dictionary<string, string>();

        return uri.Query.TrimStart('?')
                        .Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(parameter => parameter.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries))
                        .GroupBy(parts => parts[0],
                                 parts => parts.Length > 2 ? string.Join("=", parts, 1, parts.Length - 1) : (parts.Length > 1 ? parts[1] : ""))
                        .ToDictionary(grouping => grouping.Key,
                                      grouping => string.Join(",", grouping));
    }
}

Teste

[TestClass]
public class UriHelperTest
{
    [TestMethod]
    public void DecodeQueryParameters()
    {
        DecodeQueryParametersTest("http://test/test.html", new Dictionary<string, string>());
        DecodeQueryParametersTest("http://test/test.html?", new Dictionary<string, string>());
        DecodeQueryParametersTest("http://test/test.html?key=bla/blub.xml", new Dictionary<string, string> { { "key", "bla/blub.xml" } });
        DecodeQueryParametersTest("http://test/test.html?eins=1&zwei=2", new Dictionary<string, string> { { "eins", "1" }, { "zwei", "2" } });
        DecodeQueryParametersTest("http://test/test.html?empty", new Dictionary<string, string> { { "empty", "" } });
        DecodeQueryParametersTest("http://test/test.html?empty=", new Dictionary<string, string> { { "empty", "" } });
        DecodeQueryParametersTest("http://test/test.html?key=1&", new Dictionary<string, string> { { "key", "1" } });
        DecodeQueryParametersTest("http://test/test.html?key=value?&b=c", new Dictionary<string, string> { { "key", "value?" }, { "b", "c" } });
        DecodeQueryParametersTest("http://test/test.html?key=value=what", new Dictionary<string, string> { { "key", "value=what" } });
        DecodeQueryParametersTest("http://www.google.com/search?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22",
            new Dictionary<string, string>
            {
                { "q", "energy+edge" },
                { "rls", "com.microsoft:en-au" },
                { "ie", "UTF-8" },
                { "oe", "UTF-8" },
                { "startIndex", "" },
                { "startPage", "1%22" },
            });
        DecodeQueryParametersTest("http://test/test.html?key=value;key=anotherValue", new Dictionary<string, string> { { "key", "value,anotherValue" } });
    }

    private static void DecodeQueryParametersTest(string uri, Dictionary<string, string> expected)
    {
        Dictionary<string, string> parameters = new Uri(uri).DecodeQueryParameters();
        Assert.AreEqual(expected.Count, parameters.Count, "Wrong parameter count. Uri: {0}", uri);
        foreach (var key in expected.Keys)
        {
            Assert.IsTrue(parameters.ContainsKey(key), "Missing parameter key {0}. Uri: {1}", key, uri);
            Assert.AreEqual(expected[key], parameters[key], "Wrong parameter value for {0}. Uri: {1}", parameters[key], uri);
        }
    }
}

útil para o projeto Xamarin, onde HttpUtility está indisponível
Artemious

12

@Andrew and @CZFox

Eu tive o mesmo bug e achei a causa desse parâmetro, de fato: http://www.example.com?param1e não param1qual é o que se esperaria.

Removendo todos os caracteres antes e incluindo o ponto de interrogação, esse problema é corrigido. Portanto, em essência, a HttpUtility.ParseQueryStringfunção requer apenas um parâmetro válido de string de consulta contendo apenas caracteres após o ponto de interrogação, como em:

HttpUtility.ParseQueryString ( "param1=good&param2=bad" )

Minha solução alternativa:

string RawUrl = "http://www.example.com?param1=good&param2=bad";
int index = RawUrl.IndexOf ( "?" );
if ( index > 0 )
    RawUrl = RawUrl.Substring ( index ).Remove ( 0, 1 );

Uri myUri = new Uri( RawUrl, UriKind.RelativeOrAbsolute);
string param1 = HttpUtility.ParseQueryString( myUri.Query ).Get( "param1" );`

Quando o URI é instanciado, recebo o erro "URI inválido: não foi possível determinar o formato do URI". Não acho que essa solução funcione conforme o esperado.
Paul Matthews

@PaulMatthews, você está correto. No momento desta solução, eu estava usando o antigo .net framework 2.0. Para confirmar, sua declaração, copiei e colei esta solução no LINQPad v2 por Joseph Albahara e recebi o mesmo erro que você mencionou.
Mo Gauvin

@PaulMatthews, para corrigir, remova a linha que lê Uri myUri = new Uri (RawUrl); e apenas passe RawUrl para a última instrução como em: string param1 = HttpUtility.ParseQueryString (RawUrl) .Get ("param2");
Mo Gauvin

Sim, o fato de analisar apenas a parte da string de consulta está no nome e na documentação. Não é um bug. Eu nem tenho certeza de como eles poderiam deixar isso mais claro. ParseQueryStringanalisa cadeias de consulta.
PandaWood

12

Parece que você deve fazer um loop sobre os valores de myUri.Querye analisá-lo a partir daí.

 string desiredValue;
 foreach(string item in myUri.Query.Split('&'))
 {
     string[] parts = item.Replace("?", "").Split('=');
     if(parts[0] == "desiredKey")
     {
         desiredValue = parts[1];
         break;
     }
 }

No entanto, eu não usaria esse código sem testá-lo em vários URLs malformados. Pode quebrar em alguns / todos estes:

  • hello.html?
  • hello.html?valuelesskey
  • hello.html?key=value=hi
  • hello.html?hi=value?&b=c
  • etc

4

Você pode usar a seguinte solução alternativa para que funcione também com o primeiro parâmetro:

var param1 =
    HttpUtility.ParseQueryString(url.Substring(
        new []{0, url.IndexOf('?')}.Max()
    )).Get("param1");

2

Use o .NET Reflector para visualizar o FillFromStringmétodo de System.Web.HttpValueCollection. Isso fornece o código que o ASP.NET está usando para preencher a Request.QueryStringcoleção.


1

Ou, se você não souber o URL (para evitar a codificação, use o AbsoluteUri

Exemplo ...

        //get the full URL
        Uri myUri = new Uri(Request.Url.AbsoluteUri);
        //get any parameters
        string strStatus = HttpUtility.ParseQueryString(myUri.Query).Get("status");
        string strMsg = HttpUtility.ParseQueryString(myUri.Query).Get("message");
        switch (strStatus.ToUpper())
        {
            case "OK":
                webMessageBox.Show("EMAILS SENT!");
                break;
            case "ER":
                webMessageBox.Show("EMAILS SENT, BUT ... " + strMsg);
                break;
        }

0

se você deseja obter sua página QueryString na página padrão, a página padrão significa o URL da página atual. você pode tentar este código:

string paramIl = HttpUtility.ParseQueryString(this.ClientQueryString).Get("city");

0

Isso é realmente muito simples e funcionou para mim :)

        if (id == "DK")
        {
            string longurl = "selectServer.aspx?country=";
            var uriBuilder = new UriBuilder(longurl);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            query["country"] = "DK";

            uriBuilder.Query = query.ToString();
            longurl = uriBuilder.ToString();
        } 

0

Para quem deseja fazer um loop através de todas as seqüências de consulta de uma sequência

        foreach (var item in new Uri(urlString).Query.TrimStart('?').Split('&'))
        {
            var subStrings = item.Split('=');

            var key = subStrings[0];
            var value = subStrings[1];

            // do something with values
        }


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.