NameValueCollection到URL查询?

时间:2010-10-05 17:04:44

标签: asp.net url url-encoding namevaluecollection

我知道我可以做到这一点

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

但有没有办法将其转换回网址?

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

13 个答案:

答案 0 :(得分:98)

只需在ToString()上调用NameValueCollection,就会以name1=value1&name2=value2 querystring ready格式返回名称值对。请注意,NameValueCollection类型实际上并不支持这种情况,并且建议这样做会产生误导,但由于实际返回的内部类型,此行为在此处起作用,如下所述。

感谢@mjwills指出HttpUtility.ParseQueryString方法实际上返回的是内部HttpValueCollection对象而不是常规NameValueCollectiondespite the documentation specifying NameValueCollection)。使用HttpValueCollection时,ToString()会自动对查询字符串进行编码,因此无需编写循环遍历集合并使用UrlEncode方法的例程。已返回所需的结果。

掌握结果后,您可以将其附加到URL并重定向:

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

目前使用HttpValueCollection的唯一方法是使用上面显示的ParseQueryString方法(当然不是反射)。看起来这不会改变,因为Connect issue requesting this class be made public已关闭,状态为“无法修复”。

另外,您可以调用Add上的SetRemovenameValues方法修改任何查询字符串项,然后再添加它们。如果您对see my response to another question感兴趣。

答案 1 :(得分:62)

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

答案 2 :(得分:13)

制作一个使用几个循环的扩展方法。我更喜欢这个解决方案,因为它是可读的(没有linq),不需要System.Web.HttpUtility,它处理重复的密钥。

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

答案 3 :(得分:11)

这应该没有太多代码:

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

我们的想法是使用HttpUtility.ParseQueryString生成类型为HttpValueCollection的空集合。此类是NameValueCollection的子类,标记为internal,因此您的代码无法轻松创建它的实例。

关于HttpValueCollection的好处是ToString方法会为您处理编码。通过利用NameValueCollection.Add(NameValueCollection)方法,您可以将现有查询字符串参数添加到新创建的对象中,而无需先将Request.QueryString集合转换为url编码的字符串,然后将其解析回集合。

此技术也可以作为扩展方法公开:

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

答案 4 :(得分:5)

实际上,您也应该对密钥进行编码,而不仅仅是值。

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

答案 5 :(得分:3)

简短的回答是在.ToString()上使用NameValueCollection并将其与原始网址结合使用。

但是,我想指出一些事情:

您无法在HttpUtility.ParseQueryString上使用Request.RawUrlParseQueryString()方法正在寻找这样的值:?var=value&var2=value2

如果您想获得NameValueCollectionQueryString参数,请使用Request.QueryString()

var nv = Request.QueryString;

要重建URL,只需使用nv.ToString()。

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

如果您尝试解析网址字符串而不是使用Request对象,请使用UriHttpUtility.ParseQueryString方法。

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

答案 6 :(得分:3)

因为NameValueCollection可以为同一个键设置多个值,如果您关注查询字符串的格式(因为它将以逗号分隔值而不是“数组表示法”返回),您可以考虑以下。

实施例

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

转入:key1=val1&key2[]=val2&empty&key2[]=val2b而不是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)
        );
    })
);

或者如果你不喜欢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);
            }
        }
    }
}

正如评论中已经指出的那样,除了this answer之外,大多数其他答案都解决了这个问题(Request.QueryStringHttpValueCollection,而不是“{{1}而不是文字问题。

更新:通过评论解决了空值问题。

答案 7 :(得分:1)

这对你有用吗?

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(); }
}

使用:

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

答案 8 :(得分:1)

在AspNet Core 2.0中,您可以使用QueryHelpers AddQueryString方法。

答案 9 :(得分:0)

你可以使用。

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

如果此nv是string类型,则可以追加到uri第一个参数。 喜欢

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

答案 10 :(得分:0)

我总是使用UriBuilder将带有查询字符串的网址转换回有效且编码正确的网址。

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

答案 11 :(得分:0)

按照@Atchitutchuk的建议,您可以在ASP.NET Core中使用QueryHelpers.AddQueryString:

    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('?');
    }

答案 12 :(得分:0)

这对我有用:

public ActionResult SetLanguage(string language = "fr_FR")
        {            
            Request.UrlReferrer.TryReadQueryAs(out RouteValueDictionary parameters);            
            parameters["language"] = language;            
            return RedirectToAction("Index", parameters);            
        }