Ottieni parametri url da una stringa in .NET


239

Ho una stringa in .NET che in realtà è un URL. Voglio un modo semplice per ottenere il valore da un determinato parametro.

Normalmente, userei solo Request.Params["theThingIWant"], ma questa stringa non proviene dalla richiesta. Posso creare un nuovo Urioggetto in questo modo:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

Posso usare myUri.Queryper ottenere la stringa di query ... ma a quanto pare devo trovare un modo regexy di dividerlo.

Mi sto perdendo qualcosa di ovvio o non esiste un modo per fare questo a meno di creare una regex di qualche tipo, ecc.?

Risposte:


494

Utilizzare il ParseQueryStringmetodo statico della System.Web.HttpUtilityclasse che restituisce NameValueCollection.

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

Consultare la documentazione su http://msdn.microsoft.com/en-us/library/ms150046.aspx


14
Questo non sembra rilevare il primo parametro. ad esempio, l'analisi di " google.com/… " non rileva il parametro q
Andrew Shepherd,

@Andrew confermo. È strano (bug?). Puoi comunque usare HttpUtility.ParseQueryString(myUri.Query).Get(0)e estrarrà il primo parametro. `
Mariusz Pawelski il

Qualche strumento .NET per creare un URL di query con parametri?
Shimmy Weitzhandler,

6
Non puoi analizzare gli URL di query completi con HttpUtility.ParseQueryString(string)! Come dice il nome, deve analizzare le stringhe di query, non gli URL con parametri di query. Se vuoi farlo, devi prima dividerlo in ?questo modo: Url.Split('?')e ottenere l'ultimo elemento usando (a seconda della situazione e di cosa hai bisogno) [0]o LINQ Last()/ LastOrDefault().
Kosiek,

1
Quando lo provo io stesso, la firma sembra essere cambiata in questo: HttpUtility.ParseQueryString (uri.Query) .GetValues ​​("param1"). First ()
The Senator

48

Questo è probabilmente quello che vuoi

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

Ecco un'altra alternativa se, per qualsiasi motivo, non puoi o non vuoi usare HttpUtility.ParseQueryString().

Questo è costruito per essere un po 'tollerante alle stringhe di query "malformate", ovvero http://test/test.html?empty=diventa un parametro con un valore vuoto. Il chiamante può verificare i parametri se necessario.

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

Test

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

utile per il progetto Xamarin, dove HttpUtility non è disponibile
Artemious

12

@Andrew e @CZFox

Ho avuto lo stesso bug e ho scoperto che la causa è che il parametro uno è in realtà: http://www.example.com?param1e non param1è quello che ci si aspetterebbe.

Rimuovendo tutti i caratteri prima e includendo il punto interrogativo si risolve questo problema. Quindi, in sostanza, la HttpUtility.ParseQueryStringfunzione richiede solo un parametro di stringa di query valido contenente solo caratteri dopo il punto interrogativo come in:

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

La mia soluzione 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 l'URI viene istanziato, viene visualizzato l'errore "URI non valido: impossibile determinare il formato dell'URI". Non penso che questa soluzione funzioni come previsto.
Paul Matthews,

@PaulMatthews, hai ragione. Al momento di questa soluzione, stavo usando il vecchio .net framework 2.0. Per confermare, la tua dichiarazione, ho copiato e incollato questa soluzione in LINQPad v2 da Joseph Albahara e ho ricevuto lo stesso errore che hai menzionato.
Mo Gauvin,

@PaulMatthews, Per correggere, rimuovere la riga che legge Uri myUri = new Uri (RawUrl); e passa semplicemente RawUrl all'ultima istruzione come in: stringa param1 = HttpUtility.ParseQueryString (RawUrl) .Get ("param2");
Mo Gauvin,

Sì, il fatto che analizzi solo la parte della stringa di query è nel nome e nella documentazione. Non è un bug. Non sono nemmeno sicuro di come possano renderlo più chiaro. ParseQueryStringanalizza le stringhe di query.
PandaWood,

12

Sembra che dovresti scorrere i valori di myUri.Querye analizzarlo da lì.

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

Non userei questo codice senza testarlo su un sacco di URL non validi. Potrebbe rompersi su alcuni / tutti questi:

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

4

È possibile utilizzare la seguente soluzione alternativa affinché funzioni anche con il primo parametro:

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

2

Utilizzare .NET Reflector per visualizzare il FillFromStringmetodo di System.Web.HttpValueCollection. Questo ti dà il codice che ASP.NET sta usando per riempire la Request.QueryStringraccolta.


1

O se non conosci l'URL (per evitare la codifica, usa il AbsoluteUri

Esempio ...

        //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 desideri ottenere QueryString nella pagina predefinita. Pagina predefinita indica l'URL della pagina corrente. puoi provare questo codice:

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

0

Questo in realtà è molto semplice e ha funzionato per me :)

        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

Per chiunque desideri eseguire il ciclo tra tutte le stringhe di query da una stringa

        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
        }


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.