Comment créer une chaîne de requête pour une URL en C #?

Une tâche courante lors de l’appel de ressources Web à partir d’un code consiste à créer une chaîne de requête pour inclure tous les parameters nécessaires. Bien que ce ne soit pas du tout une science de la fusée, il y a des détails astucieux dont vous devez vous occuper, en ajoutant un & sinon le premier paramètre, en encodant les parameters, etc.

Le code pour le faire est très simple, mais un peu fastidieux:

 SsortingngBuilder SB = new SsortingngBuilder(); 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")); } } 

C’est une tâche si commune que l’on pourrait s’attendre à une classe d’utilitaires qui la rende plus élégante et lisible. Scanner MSDN, je n’ai pas réussi à en trouver un – ce qui m’amène à la question suivante:

Quelle est la manière la plus élégante et la plus propre que vous ayez de faire ci-dessus?

Si vous regardez sous le capot, la propriété QuerySsortingng est un NameValueCollection. Lorsque j’ai fait des choses similaires, je me suis généralement intéressé à la sérialisation ET à la désérialisation. Je suggère donc de créer un NameValueCollection, puis de passer à:

 using System.Web; using System.Collections.Specialized; private ssortingng ToQuerySsortingng(NameValueCollection nvc) { var array = (from key in nvc.AllKeys from value in nvc.GetValues(key) select ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value))) .ToArray(); return "?" + ssortingng.Join("&", array); } 

Peut-être aurais-je pu mieux le formater 🙂

J’imagine qu’il y a aussi une façon très élégante de le faire dans LINQ aussi …

Vous pouvez créer une nouvelle instance HttpValueCollection en écriture de HttpValueCollection en appelant System.Web.HttpUtility.ParseQuerySsortingng(ssortingng.Empty) , puis en l’utilisant comme NameValueCollection . Une fois que vous avez ajouté les valeurs de votre choix, vous pouvez appeler ToSsortingng sur la collection pour obtenir une chaîne de requête, comme suit:

 NameValueCollection querySsortingng = System.Web.HttpUtility.ParseQuerySsortingng(ssortingng.Empty); querySsortingng["key1"] = "value1"; querySsortingng["key2"] = "value2"; return querySsortingng.ToSsortingng(); // Returns "key1=value1&key2=value2", all URL-encoded 

HttpValueCollection est interne et vous ne pouvez donc pas HttpValueCollection directement une instance. Cependant, une fois que vous obtenez une instance, vous pouvez l’utiliser comme n’importe quelle autre NameValueCollection . L’object que vous HttpValueCollection étant un object HttpValueCollection , l’appel de la méthode ToSsortingng appellera la méthode substituée sur HttpValueCollection , qui formate la collection en tant que chaîne de requête codée en URL.

Après avoir effectué une recherche sur SO et sur le Web pour trouver une réponse à un problème similaire, voici la solution la plus simple que je puisse trouver.

.NET Core

Si vous travaillez dans .NET Core, vous pouvez utiliser la classe Microsoft.AspNetCore.WebUtilities.QueryHelpers , ce qui simplifie grandement cette procédure.

https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.webutilities.queryhelpers

Avec l’inspiration du commentaire de Roy Tinker, j’ai fini par utiliser une méthode d’extension simple sur la classe Uri qui garde mon code concis et propre:

 using System.Web; public static class HttpExtensions { public static Uri AddQuery(this Uri uri, ssortingng name, ssortingng value) { var httpValueCollection = HttpUtility.ParseQuerySsortingng(uri.Query); httpValueCollection.Remove(name); httpValueCollection.Add(name, value); var ub = new UriBuilder(uri); ub.Query = httpValueCollection.ToSsortingng(); return ub.Uri; } } 

Usage:

 Uri url = new Uri("http://localhost/rest/something/browse"). AddQuery("page", "0"). AddQuery("pageSize", "200"); 

Edit – Variante conforme aux normes

Comme plusieurs personnes l’ont souligné, httpValueCollection.ToSsortingng() encode les caractères Unicode d’une manière non conforme aux normes . Il s’agit d’une variante de la même méthode d’extension qui gère ces caractères en HttpUtility.UrlEncode méthode HttpUtility.UrlEncode au lieu de la méthode HttpUtility.UrlEncodeUnicode obsolète.

 using System.Web; public static Uri AddQuery(this Uri uri, ssortingng name, ssortingng value) { var httpValueCollection = HttpUtility.ParseQuerySsortingng(uri.Query); httpValueCollection.Remove(name); httpValueCollection.Add(name, value); var ub = new UriBuilder(uri); // this code block is taken from httpValueCollection.ToSsortingng() method // and modified so it encodes ssortingngs with HttpUtility.UrlEncode if (httpValueCollection.Count == 0) ub.Query = Ssortingng.Empty; else { var sb = new SsortingngBuilder(); for (int i = 0; i < httpValueCollection.Count; i++) { string text = httpValueCollection.GetKey(i); { text = HttpUtility.UrlEncode(text); string val = (text != null) ? (text + "=") : string.Empty; string[] vals = httpValueCollection.GetValues(i); if (sb.Length > 0) sb.Append('&'); if (vals == null || vals.Length == 0) sb.Append(val); else { if (vals.Length == 1) { sb.Append(val); sb.Append(HttpUtility.UrlEncode(vals[0])); } else { for (int j = 0; j < vals.Length; j++) { if (j > 0) sb.Append('&'); sb.Append(val); sb.Append(HttpUtility.UrlEncode(vals[j])); } } } } } ub.Query = sb.ToSsortingng(); } return ub.Uri; } 

J’ai déjà répondu à une question similaire . Fondamentalement, le meilleur moyen serait d’utiliser la classe HttpValueCollection , qui est la propriété Request.QuerySsortingng d’ASP.NET, malheureusement, elle est interne au framework .NET. Vous pouvez utiliser Reflector pour le saisir (et le placer dans votre classe Utils). De cette façon, vous pouvez manipuler la chaîne de requête comme un NameValueCollection, mais avec tous les problèmes d’encodage / décodage d’url pris en charge pour vous.

HttpValueCollection étend NameValueCollection et possède un constructeur qui prend une chaîne de requête codée (esperluettes et points d’interrogation inclus) et remplace une méthode ToSsortingng() pour reconstruire ultérieurement la chaîne de requête à partir de la collection sous-jacente.

Exemple:

  var coll = new HttpValueCollection(); coll["userId"] = "50"; coll["paramA"] = "A"; coll["paramB"] = "B"; ssortingng query = coll.ToSsortingng(true); // true means use urlencode Console.WriteLine(query); // prints: userId=50&paramA=A&paramB=B 

Voici une méthode fluide / lambda-ish en tant que méthode d’extension (combinaison de concepts dans des publications précédentes) qui prend en charge plusieurs valeurs pour la même clé. Ma préférence personnelle concerne les extensions sur les wrappers pour la capacité de découverte par d’autres membres de l’équipe pour des choses comme ça. Notez qu’il existe une controverse autour des méthodes d’encodage, de nombreuses publications à ce sujet sur Stack Overflow (un tel poste ) et des blogueurs MSDN (comme celui-ci ).

 public static ssortingng ToQuerySsortingng(this NameValueCollection source) { return Ssortingng.Join("&", source.AllKeys .SelectMany(key => source.GetValues(key) .Select(value => Ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)))) .ToArray()); } 

edit: avec un support nul, mais vous devrez probablement l’adapter à votre situation particulière

 public static ssortingng ToQuerySsortingng(this NameValueCollection source, bool removeEmptyEnsortinges) { return source != null ? Ssortingng.Join("&", source.AllKeys .Where(key => !removeEmptyEnsortinges || source.GetValues(key) .Where(value => !Ssortingng.IsNullOrEmpty(value)) .Any()) .SelectMany(key => source.GetValues(key) .Where(value => !removeEmptyEnsortinges || !Ssortingng.IsNullOrEmpty(value)) .Select(value => Ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(key), value != null ? HttpUtility.UrlEncode(value) : ssortingng.Empty))) .ToArray()) : ssortingng.Empty; } 

Flurl [divulgation: I’m the author] prend en charge la création de chaînes de requête via des objects anonymes (entre autres):

 var url = "http://www.some-api.com".SetQueryParams(new { api_key = ConfigurationManager.AppSettings["SomeApiKey"], max_results = 20, q = "Don't worry, I'll get encoded!" }); 

Le compagnon optionnel Flurl.Http lib vous permet d’effectuer des appels HTTP directement sur la même chaîne d’appels courante, en l’étendant à un client REST complet:

 await "https://api.mysite.com" .AppendPathSegment("person") .SetQueryParams(new { ap_key = "my-key" }) .WithOAuthBearerToken("MyToken") .PostJsonAsync(new { first_name = firstName, last_name = lastName }); 

Le package complet est disponible sur NuGet:

PM> Install-Package Flurl.Http

ou juste le générateur d’URL autonome:

PM> Install-Package Flurl

Voici mon entrée tardive. Je n’aimais pas les autres pour diverses raisons, alors j’ai écrit les miennes.

Cette version dispose de:

  • Utilisation de SsortingngBuilder uniquement. Pas d’appels ToArray () ou d’autres méthodes d’extension. Cela ne semble pas aussi beau que certaines des autres réponses, mais je considère que c’est une fonction essentielle, donc l’efficacité est plus importante que d’avoir un code “fluide”, “à une seule ligne” qui cache les inefficacités.

  • Gère plusieurs valeurs par clé. (J’en avais pas besoin mais juste pour faire taire Mauricio)

     public ssortingng ToQuerySsortingng(NameValueCollection nvc) { SsortingngBuilder sb = new SsortingngBuilder("?"); bool first = true; foreach (ssortingng key in nvc.AllKeys) { foreach (ssortingng value in nvc.GetValues(key)) { if (!first) { sb.Append("&"); } sb.AppendFormat("{0}={1}", Uri.EscapeDataSsortingng(key), Uri.EscapeDataSsortingng(value)); first = false; } } return sb.ToSsortingng(); } 

Exemple d’utilisation

  var queryParams = new NameValueCollection() { { "x", "1" }, { "y", "2" }, { "foo", "bar" }, { "foo", "baz" }, { "special chars", "? = &" }, }; ssortingng url = "http://example.com/stuff" + ToQuerySsortingng(queryParams); Console.WriteLine(url); 

Sortie

 http://example.com/stuff?x=1&y=2&foo=bar&foo=baz&special%20chars=%3F%20%3D%20%26 

Que diriez-vous de créer des méthodes d’extension qui vous permettent d’append les parameters dans un style fluide comme celui-ci?

 ssortingng a = "http://www.somedomain.com/somepage.html" .AddQueryParam("A", "TheValueOfA") .AddQueryParam("B", "TheValueOfB") .AddQueryParam("Z", "TheValueOfZ"); ssortingng b = new SsortingngBuilder("http://www.somedomain.com/anotherpage.html") .AddQueryParam("A", "TheValueOfA") .AddQueryParam("B", "TheValueOfB") .AddQueryParam("Z", "TheValueOfZ") .ToSsortingng(); 

Voici la surcharge qui utilise une ssortingng :

 public static ssortingng AddQueryParam( this ssortingng source, ssortingng key, ssortingng value) { ssortingng delim; if ((source == null) || !source.Contains("?")) { delim = "?"; } else if (source.EndsWith("?") || source.EndsWith("&")) { delim = ssortingng.Empty; } else { delim = "&"; } return source + delim + HttpUtility.UrlEncode(key) + "=" + HttpUtility.UrlEncode(value); } 

Et voici la surcharge qui utilise un SsortingngBuilder :

 public static SsortingngBuilder AddQueryParam( this SsortingngBuilder source, ssortingng key, ssortingng value) { bool hasQuery = false; for (int i = 0; i < source.Length; i++) { if (source[i] == '?') { hasQuery = true; break; } } string delim; if (!hasQuery) { delim = "?"; } else if ((source[source.Length - 1] == '?') || (source[source.Length - 1] == '&')) { delim = string.Empty; } else { delim = "&"; } return source.Append(delim).Append(HttpUtility.UrlEncode(key)) .Append("=").Append(HttpUtility.UrlEncode(value)); } 

Je devais résoudre le même problème pour une bibliothèque de classes portable (PCL) sur laquelle je travaille. Dans ce cas, je n’ai pas access à System.Web donc je ne peux pas utiliser ParseQuerySsortingng.

Au lieu de cela, j’ai utilisé System.Net.Http.FormUrlEncodedContent comme System.Net.Http.FormUrlEncodedContent :

 var url = new UriBuilder("http://example.com"); url.Query = new FormUrlEncodedContent(new Dictionary() { {"param1", "val1"}, {"param2", "val2"}, {"param3", "val3"}, }).ReadAsSsortingngAsync().Result; 
  public static ssortingng ToQuerySsortingng(this Dictionary source) { return Ssortingng.Join("&", source.Select(kvp => Ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value))).ToArray()); } public static ssortingng ToQuerySsortingng(this NameValueCollection source) { return Ssortingng.Join("&", source.Cast().Select(key => Ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(source[key]))).ToArray()); } 

Mon offre:

 public static Uri AddQuery(this Uri uri, ssortingng name, ssortingng value) { // this actually returns HttpValueCollection : NameValueCollection // which uses unicode compliant encoding on ToSsortingng() var query = HttpUtility.ParseQuerySsortingng(uri.Query); query.Add(name, value); var uriBuilder = new UriBuilder(uri) { Query = query.ToSsortingng() }; return uriBuilder.Uri; } 

Usage:

 var uri = new Uri("http://stackoverflow.com").AddQuery("such", "method") .AddQuery("wow", "soFluent"); // http://stackoverflow.com?such=method&wow=soFluent 

Ajouter cette classe à votre projet

 using System; using System.Collections.Generic; using System.Linq; using System.Web; public class QuerySsortingngBuilder { private readonly List> _list; public QuerySsortingngBuilder() { _list = new List>(); } public void Add(ssortingng name, object value) { _list.Add(new KeyValuePair(name, value)); } public override ssortingng ToSsortingng() { return Ssortingng.Join("&", _list.Select(kvp => Ssortingng.Concat(Uri.EscapeDataSsortingng(kvp.Key), "=", Uri.EscapeDataSsortingng(kvp.Value.ToSsortingng())))); } } 

Et l’utiliser comme ça:

 var actual = new QuerySsortingngBuilder { {"foo", 123}, {"bar", "val31"}, {"bar", "val32"} }; actual.Add("a+b", "c+d"); actual.ToSsortingng(); // "foo=123&bar=val31&bar=val32&a%2bb=c%2bd" 

Non testé, mais je pense que quelque chose dans ce sens fonctionnerait très bien

 public class QuerySsortingng { private Dictionary _Params = new Dictionary(); public overide ToSsortingng() { List returnParams = new List(); foreach (KeyValuePair param in _Params) { returnParams.Add(Ssortingng.Format("{0}={1}", param.Key, param.Value)); } // return Ssortingng.Format("?{0}", Ssortingng.Join("&", returnParams.ToArray())); // credit annakata return "?" + Ssortingng.Join("&", returnParams.ToArray()); } public void Add(ssortingng key, ssortingng value) { _Params.Add(key, HttpUtility.UrlEncode(value)); } } QuerySsortingng query = new QuerySsortingng(); query.Add("param1", "value1"); query.Add("param2", "value2"); return query.ToSsortingng(); 

Une version basée sur une méthode d’extension rapide:

 class Program { static void Main(ssortingng[] args) { var parameters = new List> { new KeyValuePair("A", "AValue"), new KeyValuePair("B", "BValue") }; ssortingng output = "?" + ssortingng.Join("&", parameters.ConvertAll(param => param.ToQuerySsortingng()).ToArray()); } } public static class KeyValueExtensions { public static ssortingng ToQuerySsortingng(this KeyValuePair obj) { return obj.Key + "=" + HttpUtility.UrlEncode(obj.Value); } } 

Vous pouvez utiliser une clause where pour sélectionner les parameters ajoutés à la chaîne.

En supposant que vous souhaitiez réduire les dépendances par rapport aux autres assemblages et que les choses restnt simples, vous pouvez:

 var sb = new System.Text.SsortingngBuilder(); sb.Append("a=" + HttpUtility.UrlEncode("TheValueOfA") + "&"); sb.Append("b=" + HttpUtility.UrlEncode("TheValueOfB") + "&"); sb.Append("c=" + HttpUtility.UrlEncode("TheValueOfC") + "&"); sb.Append("d=" + HttpUtility.UrlEncode("TheValueOfD") + "&"); sb.Remove(sb.Length-1, 1); // Remove the final '&' ssortingng result = sb.ToSsortingng(); 

Cela fonctionne bien avec les boucles aussi. La suppression finale de l’esperluette doit sortir de la boucle.

Notez que l’opérateur de concaténation est utilisé pour améliorer la lisibilité. Le coût de son utilisation par rapport au coût d’utilisation d’un SsortingngBuilder est minime (je pense que Jeff Atwood a posté quelque chose sur ce sujet).

[Aussi entrée tardive]

Classe d’encapsulation en chaîne pour HttpValueCollection:

 namespace System.Web.Mvc { public class QuerySsortingngBuilder { private NameValueCollection collection; public QuerySsortingngBuilder() { collection = System.Web.HttpUtility.ParseQuerySsortingng(ssortingng.Empty); } public QuerySsortingngBuilder Add(ssortingng key, ssortingng value) { collection.Add(key, value); return this; } public QuerySsortingngBuilder Remove(ssortingng key) { collection.Remove(key); return this; } public ssortingng this[ssortingng key] { get { return collection[key]; } set { collection[key] = value; } } public ssortingng ToSsortingng() { return collection.ToSsortingng(); } } } 

Exemple d’utilisation:

 QuerySsortingngBuilder parameters = new QuerySsortingngBuilder() .Add("view", ViewBag.PageView) .Add("page", ViewBag.PageNumber) .Add("size", ViewBag.PageSize); ssortingng querySsortingng = parameters.ToSsortingng(); 

Identique à la solution acceptée, mais transfred en “dot” syntaxe LINQ …

 private ssortingng ToQuerySsortingng(NameValueCollection nvc) { if (nvc == null) return Ssortingng.Empty; var queryParams = ssortingng.Join("&", nvc.AllKeys.Select(key => ssortingng.Join("&", nvc.GetValues(key).Select(v => ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(v)))))); return "?" + queryParams; } 

Combiné les meilleures réponses pour créer une version d’object anonyme :

 var querySsortingng = HttpUtility2.BuildQuerySsortingng(new { key2 = "value2", key1 = "value1", }); 

Cela génère ceci:

key2 = valeur2 & clé1 = valeur1

Voici le code:

 public static class HttpUtility2 { public static ssortingng BuildQuerySsortingng(T obj) { var querySsortingng = HttpUtility.ParseQuerySsortingng(ssortingng.Empty); foreach (var property in TypeDescriptor.GetProperties(typeof(T)).Cast()) { var value = (property.GetValue(obj) ?? "").ToSsortingng(); querySsortingng.Add(property.Name, value); } return querySsortingng.ToSsortingng(); } } 

J’ai une méthode d’extension pour Uri qui:

  • Accepte les objects anonymes: uri.WithQuery(new { name = "value" })
  • Accepte les collections de paires ssortingng/ssortingng (par exemple Dictionary`2 ).
  • Accepte des collections de paires ssortingng/object (par exemple RouteValueDictionary ).
  • Accepte NameValueCollection s.
  • Trie les valeurs de requête par clé pour que les mêmes valeurs produisent des URI égaux.
  • Prend en charge plusieurs valeurs par clé, en préservant leur ordre d’origine.

La version documentée peut être trouvée ici .

L’extension:

 public static Uri WithQuery(this Uri uri, object values) { if (uri == null) throw new ArgumentNullException(nameof(uri)); if (values != null) { var query = ssortingng.Join( "&", from p in ParseQueryValues(values) where !ssortingng.IsNullOrWhiteSpace(p.Key) let k = HttpUtility.UrlEncode(p.Key.Trim()) let v = HttpUtility.UrlEncode(p.Value) orderby k select ssortingng.IsNullOrEmpty(v) ? k : $"{k}={v}"); if (query.Length != 0 || uri.Query.Length != 0) uri = new UriBuilder(uri) { Query = query }.Uri; } return uri; } 

L’parsingur de requête:

 private static IEnumerable> ParseQueryValues(object values) { // Check if a name/value collection. var nvc = values as NameValueCollection; if (nvc != null) return from key in nvc.AllKeys from val in nvc.GetValues(key) select new KeyValuePair(key, val); // Check if a ssortingng/ssortingng dictionary. var ssd = values as IEnumerable>; if (ssd != null) return ssd; // Check if a ssortingng/object dictionary. var sod = values as IEnumerable>; if (sod == null) { // Check if a non-generic dictionary. var ngd = values as IDictionary; if (ngd != null) sod = ngd.Cast().ToDictionary( p => p.Key.ToSsortingng(), p => p.Value as object); // Convert object properties to dictionary. if (sod == null) sod = new RouteValueDictionary(values); } // Normalize and return the values. return from pair in sod from val in pair.Value as IEnumerable ?? new[] { pair.Value?.ToSsortingng() } select new KeyValuePair(pair.Key, val); } 

Voici les tests:

 var uri = new Uri("https://stackoverflow.com/yo?oldKey=oldValue"); // Test with a ssortingng/ssortingng dictionary. var q = uri.WithQuery(new Dictionary { ["k1"] = ssortingng.Empty, ["k2"] = null, ["k3"] = "v3" }); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?k1&k2&k3=v3")); // Test with a ssortingng/object dictionary. q = uri.WithQuery(new Dictionary { ["k1"] = "v1", ["k2"] = new[] { "v2a", "v2b" }, ["k3"] = null }); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?k1=v1&k2=v2a&k2=v2b&k3")); // Test with a name/value collection. var nvc = new NameValueCollection() { ["k1"] = ssortingng.Empty, ["k2"] = "v2a" }; nvc.Add("k2", "v2b"); q = uri.WithQuery(nvc); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?k1&k2=v2a&k2=v2b")); // Test with any dictionary. q = uri.WithQuery(new Dictionary> { [1] = new HashSet { "v1" }, [2] = new HashSet { "v2a", "v2b" }, [3] = null }); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?1=v1&2=v2a&2=v2b&3")); // Test with an anonymous object. q = uri.WithQuery(new { k1 = "v1", k2 = new[] { "v2a", "v2b" }, k3 = new List { "v3" }, k4 = true, k5 = null as Queue }); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?k1=v1&k2=v2a&k2=v2b&k3=v3&k4=True&k5")); // Keep existing query using a name/value collection. nvc = HttpUtility.ParseQuerySsortingng(uri.Query); nvc.Add("newKey", "newValue"); q = uri.WithQuery(nvc); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?newKey=newValue&oldKey=oldValue")); // Merge two query objects using the RouteValueDictionary. var an1 = new { k1 = "v1" }; var an2 = new { k2 = "v2" }; q = uri.WithQuery( new RouteValueDictionary(an1).Concat( new RouteValueDictionary(an2))); Debug.Assert(q == new Uri( "https://stackoverflow.com/yo?k1=v1&k2=v2")); 

J’ai ajouté la méthode suivante à ma classe PageBase.

 protected void Redirect(ssortingng url) { Response.Redirect(url); } protected void Redirect(ssortingng url, NameValueCollection queryssortingngs) { SsortingngBuilder redirectUrl = new SsortingngBuilder(url); if (queryssortingngs != null) { for (int index = 0; index < querystrings.Count; index++) { if (index == 0) { redirectUrl.Append("?"); } redirectUrl.Append(querystrings.Keys[index]); redirectUrl.Append("="); redirectUrl.Append(HttpUtility.UrlEncode(querystrings[index])); if (index < querystrings.Count - 1) { redirectUrl.Append("&"); } } } this.Redirect(redirectUrl.ToString()); } 

Appeler:

 NameValueCollection queryssortingngs = new NameValueCollection(); queryssortingngs.Add("language", "en"); queryssortingngs.Add("id", "134"); this.Redirect("http://www.mypage.com", queryssortingngs); 

J’ai écrit des méthodes d’extension que j’ai trouvées très utiles lorsque je travaillais avec QuerySsortingngs. Souvent, je veux commencer avec le QuerySsortingng actuel et le modifier avant de l’utiliser. Quelque chose comme,

 var res = Request.QuerySsortingng.Duplicate() .ChangeField("field1", "somevalue") .ChangeField("field2", "only if following is true", true) .ChangeField("id", id, id>0) .WriteLocalPathWithQuery(Request.Url)); //Uses context to write the path 

Pour plus d’informations et la source: http://www.charlesrcook.com/archive/2008/07/23/c-extension-methods-for-asp.net-query-ssortingng-operations.aspx

C’est basique, mais j’aime le style.

Je voulais juste jeter mes 2 centimes:

 public static class HttpClientExt { public static Uri AddQueryParams(this Uri uri, ssortingng query) { var ub = new UriBuilder(uri); ub.Query = ssortingng.IsNullOrEmpty(uri.Query) ? query : ssortingng.Join("&", uri.Query.Subssortingng(1), query); return ub.Uri; } public static Uri AddQueryParams(this Uri uri, IEnumerable query) { return uri.AddQueryParams(ssortingng.Join("&", query)); } public static Uri AddQueryParams(this Uri uri, ssortingng key, ssortingng value) { return uri.AddQueryParams(ssortingng.Join("=", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value))); } public static Uri AddQueryParams(this Uri uri, params KeyValuePair[] kvps) { return uri.AddQueryParams(kvps.Select(kvp => ssortingng.Join("=", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value)))); } public static Uri AddQueryParams(this Uri uri, IDictionary kvps) { return uri.AddQueryParams(kvps.Select(kvp => ssortingng.Join("=", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value)))); } public static Uri AddQueryParams(this Uri uri, NameValueCollection nvc) { return uri.AddQueryParams(nvc.AllKeys.SelectMany(nvc.GetValues, (key, value) => ssortingng.Join("=", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)))); } } 

Les docs disent que uri.Query commencera par un ? si ce n’est pas vide et que vous devez le couper si vous voulez le modifier.

Notez que HttpUtility.UrlEncode se trouve dans System.Web .

Usage:

 var uri = new Uri("https://api.del.icio.us/v1/posts/suggest").AddQueryParam("url","http://stackoverflow.com") 
 // USAGE [TestMethod] public void TestUrlBuilder() { Console.WriteLine( new UrlBuilder("http://www.google.com?A=B") .AddPath("SomePathName") .AddPath("AnotherPathName") .SetQuery("SomeQueryKey", "SomeQueryValue") .AlterQuery("A", x => x + "C")); } 

Sortie:

http://www.google.com/SomePathName/AnotherPathName?A=BC&SomeQueryKey=SomeQueryValue

The code; you can all thank me somewhere, somehow 😀

 using System; using System.Collections.Generic; using System.Linq; using System.Web; // By Demesortings Leptos namespace TheOperator.Foundation.Web { public class UrlBuilder { public ssortingng Scheme { get; set; } public ssortingng Host { get; set; } public int? Port { get; set; } public List Paths { get; set; } public SortedDictionary QueryPairs { get; set; } public UrlBuilder(ssortingng url) { this.Paths = new List(); this.QueryPairs = new SortedDictionary(); ssortingng path = null; ssortingng query = null; Uri relativeUri = null; if (!Uri.TryCreate(url, UriKind.Relative, out relativeUri)) { var uriBuilder = new UriBuilder(url); this.Scheme = uriBuilder.Scheme; this.Host = uriBuilder.Host; this.Port = uriBuilder.Port; path = uriBuilder.Path; query = uriBuilder.Query; } else { var queryIndex = url.IndexOf('?'); if (queryIndex >= 0) { path = url.Subssortingng(0, queryIndex); query = url.Subssortingng(queryIndex + 1); } else { path = url; } } this.Paths.AddRange(path.Split(new char[] { '/' }, SsortingngSplitOptions.RemoveEmptyEnsortinges)); if (query != null) { var queryKeyValuePairs = HttpUtility.ParseQuerySsortingng(query); foreach (var queryKey in queryKeyValuePairs.AllKeys) { this.QueryPairs[queryKey] = queryKeyValuePairs[queryKey]; } } } public UrlBuilder AddPath(ssortingng value) { this.Paths.Add(value); return this; } public UrlBuilder SetQuery(ssortingng key, ssortingng value) { this.QueryPairs[key] = value; return this; } public UrlBuilder RemoveQuery(ssortingng key) { this.QueryPairs.Remove(key); return this; } public UrlBuilder AlterQuery(ssortingng key, Func alterMethod, bool removeOnNull = false) { ssortingng value; this.QueryPairs.TryGetValue(key, out value); value = alterMethod(value); if (removeOnNull && value == null) { return this.RemoveQuery(key); } else { return this.SetQuery(key, value); } } public override ssortingng ToSsortingng() { var path = !ssortingng.IsNullOrWhiteSpace(this.Host) ? ssortingng.Join("/", this.Host, ssortingng.Join("/", this.Paths)) : ssortingng.Join("/", this.Paths); var query = ssortingng.Join("&", this.QueryPairs.Select(x => ssortingng.Concat(x.Key, "=", HttpUtility.UrlEncode(x.Value)))); return ssortingng.Concat( !ssortingng.IsNullOrWhiteSpace(this.Scheme) ? ssortingng.Concat(this.Scheme, "://") : null, path, !ssortingng.IsNullOrWhiteSpace(query) ? ssortingng.Concat("?", query) : null); } } } 

I went with the solution proposed by DSO (answered on Aug 2 ’11 at 7:29), his solution does not require using HttpUtility. However, as per an article posted in Dotnetpearls , using a Dictionary is faster (in performance) than using NameValueCollection. Here is DSO’s solution modified to use Dictionary in place of NameValueCollection.

  public static Dictionary QueryParametersDictionary() { var dictionary = new Dictionary(); dictionary.Add("name", "John Doe"); dictionary.Add("address.city", "Seattle"); dictionary.Add("address.state_code", "WA"); dictionary.Add("api_key", "5352345263456345635"); return dictionary; } public static ssortingng ToQuerySsortingng(Dictionary nvc) { SsortingngBuilder sb = new SsortingngBuilder(); bool first = true; foreach (KeyValuePair pair in nvc) { if (!first) { sb.Append("&"); } sb.AppendFormat("{0}={1}", Uri.EscapeDataSsortingng(pair.Key), Uri.EscapeDataSsortingng(pair.Value)); first = false; } return sb.ToSsortingng(); } 

I wrote a helper for my razor project using some of the hints from other answers.

The ParseQuerySsortingng business is necessary because we are not allowed to tamper with the QuerySsortingng object of the current request.

 @helper GetQuerySsortingngWithValue(ssortingng key, ssortingng value) { var querySsortingng = System.Web.HttpUtility.ParseQuerySsortingng(HttpContext.Current.Request.QuerySsortingng.ToSsortingng()); querySsortingng[key] = value; @Html.Raw(querySsortingng.ToSsortingng()) } 

I use it like this:

 location.search = '?@Helpers.GetQuerySsortingngWithValue("var-name", "var-value")'; 

If you want it to take more than one value, just change the parameters to a Dictionary and add the pairs to the query ssortingng.

The code below is taken off the HttpValueCollection implementation of ToSsortingng , via ILSpy, which gives you a name=value queryssortingng.

Unfortunately HttpValueCollection is an internal class which you only ever get back if you use HttpUtility.ParseQuerySsortingng() . I removed all the viewstate parts to it, and it encodes by default:

 public static class HttpExtensions { public static ssortingng ToQuerySsortingng(this NameValueCollection collection) { // This is based off the NameValueCollection.ToSsortingng() implementation int count = collection.Count; if (count == 0) return ssortingng.Empty; SsortingngBuilder ssortingngBuilder = new SsortingngBuilder(); for (int i = 0; i < count; i++) { string text = collection.GetKey(i); text = HttpUtility.UrlEncodeUnicode(text); string value = (text != null) ? (text + "=") : string.Empty; string[] values = collection.GetValues(i); if (stringBuilder.Length > 0) { ssortingngBuilder.Append('&'); } if (values == null || values.Length == 0) { ssortingngBuilder.Append(value); } else { if (values.Length == 1) { ssortingngBuilder.Append(value); ssortingng text2 = values[0]; text2 = HttpUtility.UrlEncodeUnicode(text2); ssortingngBuilder.Append(text2); } else { for (int j = 0; j < values.Length; j++) { if (j > 0) { ssortingngBuilder.Append('&'); } ssortingngBuilder.Append(value); ssortingng text2 = values[j]; text2 = HttpUtility.UrlEncodeUnicode(text2); ssortingngBuilder.Append(text2); } } } } return ssortingngBuilder.ToSsortingng(); } } 

This is the identical to the accepted answer except slightly more compact:

 private ssortingng ToQuerySsortingng(NameValueCollection nvc) { return "?" + ssortingng.Join("&", nvc.AllKeys.Select(k => ssortingng.Format("{0}={1}", HttpUtility.UrlEncode(k), HttpUtility.UrlEncode(nvc[k])))); } 

Just for those that need the VB.NET version of the top-answer:

 Public Function ToQuerySsortingng(nvc As System.Collections.Specialized.NameValueCollection) As Ssortingng Dim array As Ssortingng() = nvc.AllKeys.SelectMany(Function(key As Ssortingng) nvc.GetValues(key), Function(key As Ssortingng, value As Ssortingng) Ssortingng.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(key), System.Web.HttpUtility.UrlEncode(value))).ToArray() Return "?" + Ssortingng.Join("&", array) End Function 

And the version without LINQ:

 Public Function ToQuerySsortingng(nvc As System.Collections.Specialized.NameValueCollection) As Ssortingng Dim lsParams As New List(Of Ssortingng)() For Each strKey As Ssortingng In nvc.AllKeys Dim astrValue As Ssortingng() = nvc.GetValues(strKey) For Each strValue As Ssortingng In astrValue lsParams.Add(Ssortingng.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue))) Next ' Next strValue Next ' strKey Dim astrParams As Ssortingng() = lsParams.ToArray() lsParams.Clear() lsParams = Nothing Return "?" + Ssortingng.Join("&", astrParams) End Function ' ToQuerySsortingng 

And the C# version without LINQ:

  public static ssortingng ToQuerySsortingng(System.Collections.Specialized.NameValueCollection nvc) { List lsParams = new List(); foreach (ssortingng strKey in nvc.AllKeys) { ssortingng[] astrValue = nvc.GetValues(strKey); foreach (ssortingng strValue in astrValue) { lsParams.Add(ssortingng.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue))); } // Next strValue } // Next strKey ssortingng[] astrParams =lsParams.ToArray(); lsParams.Clear(); lsParams = null; return "?" + ssortingng.Join("&", astrParams); } // End Function ToQuerySsortingng 

Works for multiple values per key in NameValueCollection.

ex: { {"k1", "v1"}, {"k1", "v1"} } => ?k1=v1&k1=v1

 ///  /// Get query ssortingng for name value collection. ///  public static ssortingng ToQuerySsortingng(this NameValueCollection collection, bool prefixQuestionMark = true) { collection.NullArgumentCheck(); if (collection.Keys.Count == 0) { return ""; } var buffer = new SsortingngBuilder(); if (prefixQuestionMark) { buffer.Append("?"); } var append = false; for (int i = 0; i < collection.Keys.Count; i++) { var key = collection.Keys[i]; var values = collection.GetValues(key); key.NullCheck(); values.NullCheck(); foreach (var value in values) { if (append) { buffer.Append("&"); } append = true; buffer.AppendFormat("{0}={1}", key.UrlEncode(), value.UrlEncode()); } } return buffer.ToString(); } 

This is another ( maybe redundant :-] ) way for do that.

The conceptuals are the same of the Vedran answer in this page (take a look here ).

But this class is more efficient, because it iterate through all Keys only one time: when ToSsortingng is invoked.

The formatting code is also semplified and improved.

Hope that could be helpful.

 public sealed class QuerySsortingngBuilder { public QuerySsortingngBuilder() { this.inner = HttpUtility.ParseQuerySsortingng(ssortingng.Empty); } public QuerySsortingngBuilder(ssortingng querySsortingng) { this.inner = HttpUtility.ParseQuerySsortingng(querySsortingng); } public QuerySsortingngBuilder(ssortingng querySsortingng, Encoding encoding) { this.inner = HttpUtility.ParseQuerySsortingng(querySsortingng, encoding); } private readonly NameValueCollection inner; public QuerySsortingngBuilder AddKey(ssortingng key, ssortingng value) { this.inner.Add(key, value); return this; } public QuerySsortingngBuilder RemoveKey(ssortingng key) { this.inner.Remove(key); return this; } public QuerySsortingngBuilder Clear() { this.inner.Clear(); return this; } public override Ssortingng ToSsortingng() { if (this.inner.Count == 0) return ssortingng.Empty; var builder = new SsortingngBuilder(); for (int i = 0; i < this.inner.Count; i++) { if (builder.Length > 0) builder.Append('&'); var key = this.inner.GetKey(i); var values = this.inner.GetValues(i); if (key == null || values == null || values.Length == 0) continue; for (int j = 0; j < values.Length; j++) { if (j > 0) builder.Append('&'); builder.Append(HttpUtility.UrlEncode(key)); builder.Append('='); builder.Append(HttpUtility.UrlEncode(values[j])); } } return builder.ToSsortingng(); } }