Obtener parámetros de URL de una cadena en .NET


239

Tengo una cadena en .NET que en realidad es una url. Quiero una manera fácil de obtener el valor de un parámetro en particular.

Normalmente, solo usaría Request.Params["theThingIWant"], pero esta cadena no es de la solicitud. Puedo crear un nuevo Urielemento así:

Uri myUri = new Uri(TheStringUrlIWantMyValueFrom);

Puedo usar myUri.Querypara obtener la cadena de consulta ... pero luego aparentemente tengo que encontrar alguna forma regexy de dividirla.

¿Me estoy perdiendo algo obvio, o no hay una forma integrada de hacer esto, salvo crear una expresión regular de algún tipo, etc.?

Respuestas:


494

Utilice el ParseQueryStringmétodo estático de System.Web.HttpUtilityclase que devuelve NameValueCollection.

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

Consulte la documentación en http://msdn.microsoft.com/en-us/library/ms150046.aspx


14
Esto no parece detectar el primer parámetro. por ejemplo, el análisis " google.com/… " no detecta el parámetro q
Andrew Shepherd

@ Andrew lo confirmo. Es extraño (¿error?) Sin HttpUtility.ParseQueryString(myUri.Query).Get(0)embargo, aún puede usarlo y extraerá el primer parámetro. `
Mariusz Pawelski

¿Alguna herramienta .NET para construir una url de consulta parametrizada?
Shimmy Weitzhandler

66
No puede analizar URL de consulta completa con HttpUtility.ParseQueryString(string)! Como su nombre lo indica, es para analizar cadenas de consulta, no URL con parámetros de consulta. Si desea hacerlo, primero debe dividirlo de ?esta manera: Url.Split('?')y obtener el último elemento usando (dependiendo de la situación y lo que necesita) [0]o LINQ's Last()/ LastOrDefault().
Kosiek

1
Al probar esto yo mismo, la firma parece haber cambiado a esto: HttpUtility.ParseQueryString (uri.Query) .GetValues ​​("param1"). Primero ()
El senador

48

Esto es probablemente lo que quieres

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

Aquí hay otra alternativa si, por alguna razón, no puede o no quiere usar HttpUtility.ParseQueryString().

Esto está diseñado para ser algo tolerante a las cadenas de consulta "malformadas", es decir, se http://test/test.html?empty=convierte en un parámetro con un valor vacío. La persona que llama puede verificar los parámetros si es necesario.

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

Prueba

[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 el proyecto Xamarin, donde HttpUtility no está disponible
Artemious

12

@Andrew y @CZFox

Tuve el mismo error y descubrí que la causa es que ese parámetro es de hecho: http://www.example.com?param1y no param1cuál es lo que uno esperaría.

Al eliminar todos los caracteres anteriores e incluir el signo de interrogación, se soluciona este problema. Entonces, en esencia, la HttpUtility.ParseQueryStringfunción solo requiere un parámetro de cadena de consulta válido que contenga solo caracteres después del signo de interrogación como en:

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

Mi solución 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" );`

Cuando se crea una instancia del URI, aparece el error "URI no válido: no se pudo determinar el formato del URI". No creo que esta solución funcione según lo previsto.
Paul Matthews

@PaulMatthews, tienes razón. En el momento de esta solución dada, estaba usando el antiguo .net framework 2.0. Para confirmar su declaración, copié y pegué esta solución en LINQPad v2 por Joseph Albahara y recibí el mismo error que usted mencionó.
Mo Gauvin el

@PaulMatthews, para corregir, elimine la línea que dice Uri myUri = new Uri (RawUrl); y simplemente pasa RawUrl a la última instrucción como en: string param1 = HttpUtility.ParseQueryString (RawUrl) .Get ("param2");
Mo Gauvin el

Sí, el hecho de que solo analiza la parte de la cadena de consulta está en el nombre y en la documentación. No es un error. Ni siquiera estoy seguro de cómo podrían hacerlo más claro. ParseQueryStringanaliza cadenas de consulta.
PandaWood

12

Parece que deberías recorrer los valores myUri.Queryy analizarlos desde allí.

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

Sin embargo, no usaría este código sin probarlo en un montón de URL malformadas. Podría romperse en algunos / todos estos:

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

4

Puede usar la siguiente solución alternativa para que también funcione con el primer parámetro:

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

2

Use .NET Reflector para ver el FillFromStringmétodo de System.Web.HttpValueCollection. Eso le da el código que ASP.NET está usando para completar la Request.QueryStringcolección.


1

O si no conoce la URL (para evitar la codificación, use el AbsoluteUri

Ejemplo ...

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

si desea obtener su QueryString en la página predeterminada. Página predeterminada significa la URL de su página actual. puedes probar este código:

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

0

Esto es realmente muy simple, y eso funcionó para mí :)

        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 cualquiera que quiera recorrer todas las cadenas de consulta desde una cadena

        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
        }


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.