asp.net url url-encoding namevaluecollection

asp.net - NameValueCollection to URL Query?



url-encoding (11)

Sé que puedo hacerlo

var nv = HttpUtility.ParseQueryString(req.RawUrl);

Pero, ¿hay alguna forma de convertir esto a una url?

var newUrl = HttpUtility.Something("/page", nv);


Debido a que NameValueCollection puede tener múltiples valores para la misma clave, si le preocupa el formato de la cadena de consulta (dado que se devolverá como valores separados por comas en lugar de "notación de matriz"), puede considerar lo siguiente.

Ejemplo

var nvc = new NameValueCollection(); nvc.Add("key1", "val1"); nvc.Add("key2", "val2"); nvc.Add("empty", null); nvc.Add("key2", "val2b");

Convierta en: key1=val1&key2[]=val2&empty&key2[]=val2b lugar de key1=val1&key2=val2,val2b&empty .

Código

string qs = string.Join("&", // "loop" the keys nvc.AllKeys.SelectMany(k => { // "loop" the values var values = nvc.GetValues(k); if(values == null) return new[]{ k }; return nvc.GetValues(k).Select( (v,i) => // ''gracefully'' handle formatting // when there''s 1 or more values string.Format( values.Length > 1 // pick your array format: k[i]=v or k[]=v, etc ? "{0}[]={1}" : "{0}={1}" , k, HttpUtility.UrlEncode(v), i) ); }) );

o si no te gusta tanto Linq ...

string qs = nvc.ToQueryString(); // using... public static class UrlExtensions { public static string ToQueryString(this NameValueCollection nvc) { return string.Join("&", nvc.GetUrlList()); } public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) { foreach(var k in nvc.AllKeys) { var values = nvc.GetValues(k); if(values == null) { yield return k; continue; } for(int i = 0; i < values.Length; i++) { yield return // ''gracefully'' handle formatting // when there''s 1 or more values string.Format( values.Length > 1 // pick your array format: k[i]=v or k[]=v, etc ? "{0}[]={1}" : "{0}={1}" , k, HttpUtility.UrlEncode(values[i]), i); } } } }

Como ya se ha señalado en los comentarios, con la excepción de esta respuesta, la mayoría de las otras respuestas abordan el escenario ( Request.QueryString es una HttpValueCollection , "not" a NameValueCollection ) en lugar de la pregunta literal.

Actualización: se abordó el problema del valor nulo a partir del comentario.


En AspNet Core 2.0 puede usar el método QueryHelpers AddQueryString.


En realidad, también debes codificar la clave, no solo el valor.

string q = String.Join("&", nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));


Esto debería funcionar sin demasiado código:

NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty); nameValues.Add(Request.QueryString); // modify nameValues if desired var newUrl = "/page?" + nameValues;

La idea es usar HttpUtility.ParseQueryString para generar una colección vacía de tipo HttpValueCollection . Esta clase es una subclase de NameValueCollection que está marcada como internal para que su código no pueda crear fácilmente una instancia de la misma.

Lo bueno de HttpValueCollection es que el método ToString se encarga de la codificación por ti. Al aprovechar el NameValueCollection.Add(NameValueCollection) , puede agregar los parámetros de cadenas de consulta existentes a su objeto recién creado sin tener que convertir primero la colección Request.QueryString en una cadena codificada en url, y luego analizarla en una colección.

Esta técnica también puede exponerse como un método de extensión:

public static string ToQueryString(this NameValueCollection nameValueCollection) { NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty) httpValueCollection.Add(nameValueCollection); return httpValueCollection.ToString(); }


Haga un método de extensión que use un par de bucles. Prefiero esta solución porque es legible (sin linq), no requiere System.Web.HttpUtility, y maneja claves duplicadas.

public static string ToQueryString(this NameValueCollection nvc) { if (nvc == null) return string.Empty; StringBuilder sb = new StringBuilder(); foreach (string key in nvc.Keys) { if (string.IsNullOrWhiteSpace(key)) continue; string[] values = nvc.GetValues(key); if (values == null) continue; foreach (string value in values) { sb.Append(sb.Length == 0 ? "?" : "&"); sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value)); } } return sb.ToString(); }

Ejemplo

var queryParams = new NameValueCollection() { { "order_id", "0000" }, { "item_id", "1111" }, { "item_id", "2222" }, { null, "skip entry with null key" }, { "needs escaping", "special chars ? = &" }, { "skip entry with null value", null } }; Console.WriteLine(queryParams.ToQueryString());

Salida

?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26


La respuesta corta es usar .ToString() en NameValueCollection y combinarlo con la URL original.

Sin embargo, me gustaría señalar algunas cosas:

No puede usar HttpUtility.ParseQueryString en Request.RawUrl . El método ParseQueryString() busca un valor como este ?var=value&var2=value2 .

Si desea obtener una NameValueCollection de los parámetros de QueryString , simplemente use Request.QueryString() .

var nv = Request.QueryString;

Para reconstruir la URL solo use nv.ToString ().

string url = String.Format("{0}?{1}", Request.Path, nv.ToString());

Si está tratando de analizar una cadena de URL en lugar de utilizar el objeto Request use Uri y el método HttpUtility.ParseQueryString .

Uri uri = new Uri("<THE URL>"); var nv = HttpUtility.ParseQueryString(uri.Query); string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());


Puedes usar.

var ur = new Uri("/page",UriKind.Relative);

si este nv es de tipo cadena, puede agregar al primer parámetro uri. Me gusta

var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);


Que este trabajo para usted?

public static string BuildUrl(string relativeUrl, params string[] queryString) { // build queryString from string parameters char[] trimChars = { '' '', ''&'', ''?'' }; StringBuilder builder = new StringBuilder(); string sepChar = "&"; string sep = String.Empty; foreach (string q in queryString) { builder.Append(sep).Append(q.Trim(trimChars)); sep = sepChar; } if (String.IsNullOrEmpty(builder.ToString())) { return relativeUrl; } else { return relativeUrl + "?" + builder.ToString(); } }

Utilizar:

string url = BuildUrl("/mypage.apsx", "qs1=a", "qs2=b", "qs3=c");


Siempre utilizo UriBuilder para convertir una URL con una cadena de consulta de nuevo a una url válida y codificada correctamente.

var url = "http://my-link.com?foo=bar"; var uriBuilder = new UriBuilder(url); var query = HttpUtility.ParseQueryString(uriBuilder.Query); query.Add("yep", "foo&bar"); uriBuilder.Query = query.ToString(); var result = uriBuilder.ToString(); // http://my-link.com:80/?foo=bar&yep=foo%26bar


Simplemente llamando a ToString() en NameValueCollection devolverá los pares de nombre y valor en un formato de querystring listo name1=value1&name2=value2 . Tenga en cuenta que los tipos de NameValueCollection no son compatibles con esto y es engañoso sugerir esto, pero el comportamiento funciona aquí debido al tipo interno que realmente se devuelve, como se explica a continuación.

Gracias a @mjwills por señalar que el método HttpUtility.ParseQueryString realmente devuelve un objeto interno HttpValueCollection lugar de una NameValueCollection normal (a pesar de la documentación que especifica NameValueCollection ). HttpValueCollection codifica automáticamente la cadena de consulta cuando usa ToString() , por lo que no es necesario escribir una rutina que recorre la colección y utiliza el método UrlEncode . El resultado deseado ya ha sido devuelto.

Con el resultado en la mano, puede agregarlo a la URL y redirigir:

var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString()); string url = Request.Url.AbsolutePath + "?" + nameValues.ToString(); Response.Redirect(url);

Actualmente, la única forma de utilizar una HttpValueCollection es mediante el uso del método ParseQueryString que se muestra arriba (aparte del reflejo, por supuesto). Parece que esto no cambiará ya que el problema de Connect que solicita que esta clase se haga público se ha cerrado con un estado de "no se solucionará".

Como nameValues aparte, puede llamar a los métodos Add , Set y Remove en los nameValues de nameValues para modificar cualquiera de los elementos de la cadena de consulta antes de anexarlo. Si está interesado en eso, vea mi respuesta a otra pregunta .


string q = String.Join("&", nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));