¿Cómo crear una cadena de consulta para una URL en C#?

Resuelto Boaz asked hace 15 años • 42 respuestas

Una tarea común al llamar a recursos web desde un código es crear una cadena de consulta que incluya todos los parámetros necesarios. Si bien no es ninguna ciencia, hay algunos detalles ingeniosos que debes cuidar, como agregar un &parámetro, si no el primero, codificar los parámetros, etc.

El código para hacerlo es muy sencillo, pero un poco tedioso:

StringBuilder SB = new StringBuilder();
if (NeedsToAddParameter A) 
{ 
  SB.Append("A="); SB.Append(HttpUtility.UrlEncode("TheValueOfA")); 
}

if (NeedsToAddParameter B) 
{
  if (SB.Length>0) SB.Append("&"); 
  SB.Append("B="); SB.Append(HttpUtility.UrlEncode("TheValueOfB")); }
}

Esta es una tarea tan común que uno esperaría que existiera una clase de utilidad que la hiciera más elegante y legible. Al escanear MSDN, no pude encontrar ninguno, lo que me lleva a la siguiente pregunta:

¿Cuál es la forma limpia más elegante que conoces de hacer lo anterior?

Boaz avatar May 06 '09 18:05 Boaz
Aceptado

Puede crear una nueva instancia de escritura HttpValueCollectionllamando a System.Web.HttpUtility.ParseQueryString(string.Empty), y luego usarla como cualquier NameValueCollection. Una vez que haya agregado los valores que desea, puede llamar ToStringa la colección para obtener una cadena de consulta, de la siguiente manera:

NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);

queryString.Add("key1", "value1");
queryString.Add("key2", "value2");

return queryString.ToString(); // Returns "key1=value1&key2=value2", all URL-encoded

Es HttpValueCollectioninterno y, por lo tanto, no se puede construir una instancia directamente. Sin embargo, una vez que obtengas una instancia podrás usarla como cualquier otra NameValueCollection. Dado que el objeto real con el que está trabajando es un HttpValueCollection, llamar al método ToString llamará al método anulado en HttpValueCollection, que formatea la colección como una cadena de consulta codificada en URL.

Después de buscar en SO y en la web una respuesta a un problema similar, esta es la solución más simple que pude encontrar.

Núcleo .NET

Si está trabajando en .NET Core, puede usar la Microsoft.AspNetCore.WebUtilities.QueryHelpersclase, lo que simplifica enormemente esto.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers

Código de muestra:

const string url = "https://customer-information.azure-api.net/customers/search/taxnbr";
var param = new Dictionary<string, string>() { { "CIKey", "123456789" } };

var newUrl = new Uri(QueryHelpers.AddQueryString(url, param));
John Bledsoe avatar Dec 09 '2009 21:12 John Bledsoe

Si miras debajo del capó, la propiedad QueryString es NameValueCollection. Cuando hice cosas similares, generalmente me interesó serializar Y deserializar, por lo que mi sugerencia es crear una NameValueCollection y luego pasar a:

using System.Linq;
using System.Web;
using System.Collections.Specialized;

private string ToQueryString(NameValueCollection nvc)
{
    var array = (
        from key in nvc.AllKeys
        from value in nvc.GetValues(key)
            select string.Format(
                "{0}={1}",
                HttpUtility.UrlEncode(key),
                HttpUtility.UrlEncode(value))
        ).ToArray();
    return "?" + string.Join("&", array);
}

Me imagino que también hay una manera súper elegante de hacer esto en LINQ...

annakata avatar May 06 '2009 11:05 annakata