Je sais que je peux le faire
var nv = HttpUtility.ParseQueryString(req.RawUrl);
Mais y a-t-il un moyen de le reconvertir en une URL?
var newUrl = HttpUtility.Something("/page", nv);
Si vous appelez simplement ToString()
sur NameValueCollection
, les paires nom-valeur seront renvoyées au format name1=value1&name2=value2
prêt pour la chaîne de requête. Notez que les types NameValueCollection
ne prennent pas cela en charge et il est trompeur de suggérer ceci, mais le comportement fonctionne ici en raison du type interne renvoyé, comme expliqué ci-dessous.
Merci à @mjwills pour avoir signalé que la méthode HttpUtility.ParseQueryString
renvoie en réalité un objet HttpValueCollection
interne plutôt qu’un NameValueCollection
normal ( malgré la documentation spécifiant NameValueCollection
). HttpValueCollection
encode automatiquement la chaîne de requête lors de l'utilisation de ToString()
. Il n'est donc pas nécessaire d'écrire une routine qui parcourt la collection et utilise la méthode UrlEncode
. Le résultat souhaité est déjà renvoyé.
Avec le résultat en main, vous pouvez ensuite l'ajouter à l'URL et rediriger:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
Actuellement, la seule façon d'utiliser HttpValueCollection
consiste à utiliser la méthode ParseQueryString
présentée ci-dessus (autre que la réflexion, bien sûr). Il semble que cela ne changera pas, car le problème de Connect demandant à ce que cette classe soit rendue publique a été fermé avec le statut "ne sera pas résolu".
En passant, vous pouvez appeler les méthodes Add
, Set
et Remove
sur nameValues
pour modifier l'un des éléments de la chaîne de requête avant de l'ajouter. Si cela vous intéresse voir ma réponse à une autre question .
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
Cela devrait fonctionner sans trop de code:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
L'idée est d'utiliser HttpUtility.ParseQueryString
pour générer une collection vide de type HttpValueCollection
. Cette classe est une sous-classe de NameValueCollection
qui est marquée par internal
afin que votre code ne puisse pas en créer facilement une instance.
La bonne chose à propos de HttpValueCollection
est que la méthode ToString
s'occupe de l'encodage pour vous. En exploitant la méthode NameValueCollection.Add(NameValueCollection)
, vous pouvez ajouter les paramètres de chaîne de requête existants à votre objet nouvellement créé sans avoir à convertir au préalable la collection Request.QueryString
en une chaîne à codage url, puis à la réanalyser en une collection.
Cette technique peut également être exposée comme méthode d'extension:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty)
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
Créez une méthode d’extension utilisant deux boucles. Je préfère cette solution car elle est lisible (sans linq), ne nécessite pas System.Web.HttpUtility et gère les clés en double.
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();
}
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());
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
En fait, vous devez également encoder la clé, pas seulement la valeur.
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
Etant donné qu'une NameValueCollection
peut avoir plusieurs valeurs pour la même clé, si vous êtes préoccupé par le format de la chaîne de requête (puisqu'elle sera renvoyée sous forme de valeurs séparées par des virgules plutôt que de "notation de tableau"), vous pouvez prendre en compte les éléments suivants.
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
Transformez-vous en: key1=val1&key2[]=val2&empty&key2[]=val2b
plutôt que key1=val1&key2=val2,val2b&empty
.
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)
);
})
);
ou si vous n'aimez pas tellement 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);
}
}
}
}
Comme cela a déjà été souligné dans les commentaires, à l'exception de cette réponse la plupart des autres réponses traitent du scénario (Request.QueryString
est une HttpValueCollection
, "pas" une NameValueCollection
) plutôt que la question littérale.
Mise à jour: a résolu le problème de valeur null à partir d'un commentaire.
La réponse courte est d'utiliser .ToString()
sur la NameValueCollection
et de la combiner avec l'URL d'origine.
Cependant, j'aimerais souligner quelques points:
Vous ne pouvez pas utiliser HttpUtility.ParseQueryString
sur Request.RawUrl
. La méthode ParseQueryString()
recherche une valeur comme celle-ci: ?var=value&var2=value2
.
Si vous voulez obtenir une NameValueCollection
des paramètres QueryString
, utilisez simplement Request.QueryString()
.
var nv = Request.QueryString;
Pour reconstruire l'URL, utilisez simplement nv.ToString ().
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
Si vous essayez d'analyser une chaîne d'URL au lieu d'utiliser l'objet Request
, utilisez Uri
et la méthode HttpUtility.ParseQueryString
.
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
Dans AspNet Core 2.0, vous pouvez utiliser la méthode QueryHelpers AddQueryString.
Est-ce que cela fonctionnerait pour vous?
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(); }
}
Utilisation:
string url = BuildUrl("/mypage.apsx", "qs1=a", "qs2=b", "qs3=c");
Comme @Atchitutchuk l'a suggéré, vous pouvez utiliser QueryHelpers.AddQueryString dans ASP.NET Core:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}
J'utilise toujours UriBuilder pour convertir une URL avec une chaîne de requête en une URL valide et correctement codée.
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
Vous pouvez utiliser.
var ur = new Uri("/page",UriKind.Relative);
si ce nv est de type chaîne, vous pouvez ajouter au premier paramètre uri .
var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);