¿Cómo crear una cadena de consulta para una URL en C#?
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?
Puede crear una nueva instancia de escritura HttpValueCollection
llamando a System.Web.HttpUtility.ParseQueryString(string.Empty)
, y luego usarla como cualquier NameValueCollection
. Una vez que haya agregado los valores que desea, puede llamar ToString
a 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 HttpValueCollection
interno 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.QueryHelpers
clase, 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));
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...