Pobierz parametry adresu URL z ciągu w .NET


239

Mam ciąg w .NET, który w rzeczywistości jest adresem URL. Chcę w łatwy sposób uzyskać wartość z określonego parametru.

Normalnie po prostu użyłbym Request.Params["theThingIWant"], ale ten ciąg nie pochodzi z żądania. Mogę stworzyć nowy Uriprzedmiot w ten sposób:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

Mogę użyć, myUri.Queryaby uzyskać ciąg zapytania ... ale najwyraźniej muszę znaleźć jakiś dziwny sposób na podzielenie go.

Czy brakuje mi czegoś oczywistego, czy też nie ma wbudowanego sposobu na zrobienie tego poza utworzeniem jakiegoś wyrażenia regularnego itp.?

Odpowiedzi:


494

Użyj statycznej ParseQueryStringmetody System.Web.HttpUtilityklasy, która zwraca NameValueCollection.

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

Sprawdź dokumentację na stronie http://msdn.microsoft.com/en-us/library/ms150046.aspx


14
Wydaje się, że nie wykrywa to pierwszego parametru. np. parsowanie „ google.com/… ” nie wykrywa parametru q
Andrew Shepherd

@Andrew potwierdzam. To dziwne (błąd?). Możesz jednak nadal używać, HttpUtility.ParseQueryString(myUri.Query).Get(0)a to wyodrębni pierwszy parametr. `
Mariusz Pawelski,

Jakieś narzędzie .NET do zbudowania sparametryzowanego adresu URL zapytania?
Shimmy Weitzhandler,

6
Nie można parsować pełnych adresów URL zapytań HttpUtility.ParseQueryString(string)! Jak sama nazwa wskazuje, parsuje ciągi zapytań, a nie adresy URL z parametrami zapytań. Jeśli chcesz to zrobić, musisz najpierw podzielić go w ?następujący sposób: Url.Split('?')i uzyskać ostatni element za pomocą (w zależności od sytuacji i tego, czego potrzebujesz) [0]lub LINQ Last()/ LastOrDefault().
Kosiek

1
Podczas testowania tego sam, podpis wydaje się zmienić na: HttpUtility.ParseQueryString (uri.Query) .GetValues ​​("param1"). Pierwszy ()
Senator

48

To jest prawdopodobnie to, czego chcesz

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

Oto kolejna alternatywa, jeśli z jakiegokolwiek powodu nie możesz lub nie chcesz używać HttpUtility.ParseQueryString().

Zostało to zbudowane tak, aby być nieco tolerancyjnym wobec „źle sformułowanych” ciągów zapytania, tzn. http://test/test.html?empty=Staje się parametrem o pustej wartości. Osoba dzwoniąca może w razie potrzeby zweryfikować parametry.

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

pomocny w projekcie Xamarin, w którym HttpUtility jest niedostępny
Artemious

12

@Andrew i @CZFox

Miałem ten sam błąd i odkryłem, że przyczyną jest ten parametr, który w rzeczywistości jest jeden: http://www.example.com?param1a nie param1tego się można spodziewać.

Usunięcie wszystkich znaków przed znakiem zapytania i włączenie go rozwiązuje ten problem. Zasadniczo więc HttpUtility.ParseQueryStringfunkcja wymaga tylko poprawnego parametru ciągu zapytania zawierającego tylko znaki po znaku zapytania, jak w:

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

Moje obejście:

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

Po utworzeniu wystąpienia identyfikatora URI pojawia się błąd „Nieprawidłowy identyfikator URI: Nie można określić formatu identyfikatora URI”. Nie sądzę, aby to rozwiązanie działało zgodnie z przeznaczeniem.
Paul Matthews,

@PaulMatthews, masz rację. W momencie tego rozwiązania korzystałem ze starszej platformy .net 2.0. Aby potwierdzić, twoje oświadczenie, skopiowałem i wkleiłem to rozwiązanie do LINQPad v2 autorstwa Josepha Albahary i otrzymałem ten sam błąd, o którym wspomniałeś.
Mo Gauvin,

@PaulMatthews, Aby naprawić, usuń wiersz z tekstem Uri myUri = new Uri (RawUrl); i po prostu przekaż RawUrl do ostatniej instrukcji, jak w: string param1 = HttpUtility.ParseQueryString (RawUrl) .Get ("param2");
Mo Gauvin,

Tak, fakt, że analizuje tylko część ciągu zapytania, znajduje się w nazwie i dokumentacji. To nie jest błąd. Nie jestem nawet pewien, jak mogliby to wyjaśnić. ParseQueryStringanalizuje ciągi zapytań.
PandaWood

12

Wygląda na to, że powinieneś zapętlić wartości myUri.Queryi przeanalizować je stamtąd.

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

Jednak nie użyłbym tego kodu bez przetestowania go na wielu źle sformatowanych adresach URL. Może się zepsuć na niektóre / wszystkie z nich:

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

4

Możesz użyć następującego obejścia, aby działał również z pierwszym parametrem:

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

2

Użyj .NET Reflector, aby wyświetlić FillFromStringmetodę System.Web.HttpValueCollection. To daje kod, którego używa ASP.NET do wypełnienia Request.QueryStringkolekcji.


1

Lub jeśli nie znasz adresu URL (aby uniknąć zakodowania na stałe, użyj AbsoluteUri

Przykład ...

        //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

jeśli chcesz uzyskać QueryString na stronie domyślnej. Domyślna strona oznacza bieżący adres strony. możesz wypróbować ten kod:

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

0

To jest naprawdę bardzo proste i to działało dla mnie :)

        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

Dla każdego, kto chce przeglądać wszystkie ciągi zapytania z ciągu

        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
        }


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.