Obtenir les paramètres d'URL d'une chaîne dans .NET

239

J'ai une chaîne en .NET qui est en fait une URL. Je veux un moyen simple d'obtenir la valeur d'un paramètre particulier.

Normalement, j'utiliserais simplement Request.Params["theThingIWant"], mais cette chaîne ne provient pas de la demande. Je peux créer un nouvel Uriarticle comme ceci:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

Je peux utiliser myUri.Querypour obtenir la chaîne de requête ... mais ensuite, je dois apparemment trouver un moyen regexy de le diviser.

Suis-je en train de manquer quelque chose d'évident, ou n'y a-t-il pas de moyen intégré pour faire cela à court de créer une expression régulière d'une sorte, etc.?

Beska
la source

Réponses:

494

Utilisez une ParseQueryStringméthode statique de System.Web.HttpUtilityclasse qui renvoie NameValueCollection.

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

Consultez la documentation à http://msdn.microsoft.com/en-us/library/ms150046.aspx

CZFox
la source
14
Cela ne semble pas détecter le premier paramètre. Par exemple, l'analyse de " google.com/… " ne détecte pas le paramètre q
Andrew Shepherd
@Andrew je confirme. C'est étrange (bug?). Vous pouvez toujours l'utiliser HttpUtility.ParseQueryString(myUri.Query).Get(0)et il extraira le premier paramètre. `
Mariusz Pawelski
Tout outil .NET pour créer une URL de requête paramétrée?
Shimmy Weitzhandler
6
Vous ne pouvez pas analyser les URL de requête complètes avec HttpUtility.ParseQueryString(string)! Comme son nom l'indique, il s'agit d'analyser les chaînes de requête, pas les URL avec des paramètres de requête. Si vous voulez le faire, vous devez d'abord le diviser ?comme ceci: Url.Split('?')et obtenir le dernier élément en utilisant (selon la situation et ce dont vous avez besoin) [0]ou LINQ Last()/ LastOrDefault().
Kosiek
1
Lors de mon test, la signature semble avoir changé pour ceci: HttpUtility.ParseQueryString (uri.Query) .GetValues ​​("param1"). First ()
Le sénateur
48

C'est probablement ce que tu veux

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");
Sergej Andrejev
la source
34

Voici une autre alternative si, pour une raison quelconque, vous ne pouvez pas ou ne voulez pas utiliser HttpUtility.ParseQueryString().

Ceci est construit pour être quelque peu tolérant aux chaînes de requête "mal formées", c'est-à-dire qu'il http://test/test.html?empty=devient un paramètre avec une valeur vide. L'appelant peut vérifier les paramètres si nécessaire.

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

Tester

[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);
        }
    }
}
alsed42
la source
utile pour le projet Xamarin, où HttpUtility n'est pas disponible
Artemious
12

@Andrew et @CZFox

J'ai eu le même bug et j'ai trouvé la cause du fait que le paramètre un est en fait: http://www.example.com?param1et non param1ce à quoi on pourrait s'attendre.

En supprimant tous les caractères avant et en incluant le point d'interrogation, ce problème est résolu. Donc, en substance, la HttpUtility.ParseQueryStringfonction ne nécessite qu'un paramètre de chaîne de requête valide contenant uniquement des caractères après le point d'interrogation, comme dans:

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

Ma solution:

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" );`
Mo Gauvin
la source
Lorsque l'URI est instancié, j'obtiens l'erreur "URI non valide: le format de l'URI n'a pas pu être déterminé." Je ne pense pas que cette solution fonctionne comme prévu.
Paul Matthews
@PaulMatthews, vous avez raison. Au moment de cette solution donnée, j'utilisais l'ancien framework .net 2.0. Pour confirmer votre déclaration, j'ai copié et collé cette solution dans LINQPad v2 de Joseph Albahara et j'ai reçu la même erreur que vous avez mentionnée.
Mo Gauvin
@PaulMatthews, Pour corriger, supprimez la ligne qui lit Uri myUri = new Uri (RawUrl); et passez simplement RawUrl à la dernière instruction comme dans: string param1 = HttpUtility.ParseQueryString (RawUrl) .Get ("param2");
Mo Gauvin
Oui, le fait qu'il analyse uniquement la partie chaîne de requête se trouve dans le nom et dans la documentation. Ce n'est pas un bug. Je ne sais même pas comment ils pourraient rendre les choses plus claires. ParseQueryStringanalyse les chaînes de requête.
PandaWood le
12

Il semble que vous devriez parcourir les valeurs de myUri.Queryet les analyser à partir de là.

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

Je n'utiliserais pas ce code sans le tester sur un tas d'URL malformées cependant. Cela pourrait casser certains / tous ces éléments:

  • hello.html?
  • hello.html?valuelesskey
  • hello.html?key=value=hi
  • hello.html?hi=value?&b=c
  • etc
Tom Ritter
la source
4

Vous pouvez également utiliser la solution de contournement suivante pour qu'il fonctionne avec le premier paramètre:

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

Utilisez .NET Reflector pour afficher la FillFromStringméthode de System.Web.HttpValueCollection. Cela vous donne le code qu'ASP.NET utilise pour remplir la Request.QueryStringcollection.

David
la source
1

Ou si vous ne connaissez pas l'URL (afin d'éviter le codage en dur, utilisez le AbsoluteUri

Exemple ...

        //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;
        }
Fandango68
la source
0

si vous voulez obtenir votre chaîne de requête sur la page par défaut. La page par défaut signifie l'url de votre page actuelle. vous pouvez essayer ce code:

string paramIl = HttpUtility.ParseQueryString(this.ClientQueryString).Get("city");
Erhan Demirci
la source
0

C'est en fait très simple, et cela a fonctionné pour moi :)

        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();
        } 
Ralle12
la source
0

Pour tous ceux qui souhaitent parcourir toutes les chaînes de requête d'une chaîne

        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
        }
Indy411
la source
-1
HttpContext.Current.Request.QueryString.Get("id");
Hallgeir Engen
la source
1
comment l'utiliser avec une chaîne
Arun Prasad ES
-4

Je l'ai utilisé et il fonctionne parfaitement

<%=Request.QueryString["id"] %>
Hoang Huynh Nhat
la source
2
à partir d'une chaîne et non d'une chaîne de requête
Arun Prasad ES