【问题标题】:NameValueCollection to URL Query?NameValueCollection 到 URL 查询?
【发布时间】:2011-04-21 10:14:40
【问题描述】:

我知道我能做到

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

但是有没有办法将它转换回 url?

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

【问题讨论】:

    标签: asp.net url url-encoding namevaluecollection


    【解决方案1】:

    你可以使用。

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

    如果这个 nv 是字符串类型,你可以附加到 uri 第一个参数。 喜欢

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

    【讨论】:

    • +nv ... 无法正常转义。
    【解决方案2】:

    只需在NameValueCollection 上调用ToString() 即可返回name1=value1&name2=value2 查询字符串就绪格式的名称值对。请注意,NameValueCollection 类型实际上并不支持这一点,建议这样做会产生误导,但由于实际返回的内部类型,该行为在这里起作用,如下所述。

    感谢@mjwills 指出HttpUtility.ParseQueryString 方法实际上返回的是内部HttpValueCollection 对象,而不是常规的NameValueCollection (despite 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 已以“无法修复”的状态关闭。

    顺便说一句,您可以在nameValues 上调用AddSetRemove 方法来修改任何查询字符串项,然后再添加它。如果您对 see my response to another question 感兴趣。

    【讨论】:

    • 我不确定 nameValues.ToString() 是否会正确转义。
    • 其实你可以使用 qs.ToString()。这是因为 qs 不是 NameValueCollection(尽管有 HttpUtility.ParseQueryString 的方法签名)。它实际上是一个名为 System.Web.HttpValueCollection 的私有类型(您可以使用 qs.GetType() 进行检查)。 NameValueCollection.ToString() 不进行 url 编码,但 HttpValueCollection.ToString() 可以。所以你使用 StringBuilder 是完全没有必要的。
    • 我之前的评论可能不正确。 HttpValueCollection 不调用 HttpUtility.UrlEncode - 相反,它似乎调用了 HttpUtility.UrlEncodeUnicode (tinyurl.com/HttpValue)。这是一个问题,因为两者处理某些字符的方式不同(例如 é)。 UrlEncodeUnicode 的新文档似乎暗示不应该使用它 - msdn.microsoft.com/en-us/library/…
    • NameValueCollection.ToString() 返回 System.Collections.Specialized.NameValueCollection 字符串(字面意思),而不是“查询字符串就绪格式的名称值对”。
    • @IgorBrejc 谢谢,我已经更新了我的帖子,说NameValueCollection 返回预期格式是一种误导。 MSDN 文档也具有误导性,因为它说 ParseQueryString 返回一个 NameValueCollection 尽管它实际上是 HttpValueCollection 并且调用 ToString() 应该返回预期的格式,因为其余的答案提到了。
    【解决方案3】:

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

    不过,我想指出几点:

    你不能在Request.RawUrl 上使用HttpUtility.ParseQueryStringParseQueryString() 方法正在寻找这样的值:?var=value&var2=value2

    如果您想获得QueryString 参数中的NameValueCollection,只需使用Request.QueryString()

    var nv = Request.QueryString;
    

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

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

    如果您尝试解析 url 字符串而不是使用 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());
    

    【讨论】:

    • 就像对the accepted answer 的评论指出(并且基本上在这里重复),Request.QueryString 实际上不是NameValueCollection,它是HttpValueCollection 的特殊衍生品,这就是.ToString 有效的原因;在常规的 nvc 上,您必须改用 this answer 之类的东西
    【解决方案4】:
    string q = String.Join("&",
                 nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
    

    【讨论】:

    • 这个答案是唯一能正确处理 url 参数中的编码的答案。赞一个!
    • 也是唯一一个回答有关NameValueCollections 的字面问题,而不是提供的涉及HttpValueCollection 的场景
    • 如果同一个键有多个值,我认为这将无法正常工作。
    • @MartinBrown 是对的,但事实并非如此。以下是多值 namevaluecollections 的作用: uriBuilder.Query += String.Join("&", parameters.AllKeys.SelectMany(key => (parameters.GetValues(key) ?? Enumerable.Empty()).Select( val => String.Concat(key, "=", WebUtility.UrlEncode(val)))));
    • 您也应该对密钥进行编码:string q = String.Join("&amp;", nvc.AllKeys.Select(a =&gt; HttpUtility.UrlEncode(a) + "=" + HttpUtility.UrlEncode(nvc[a])));
    【解决方案5】:

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

    示例

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

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

    正如已经在 cmets 中指出的那样,除了 this answer 之外,大多数其他答案都解决了这种情况(Request.QueryStringHttpValueCollection,“不是”NameValueCollection)而不是文字问题.

    更新:解决了评论中的空值问题。

    【讨论】:

    • 好主意,但您的 linq 代码不检查 null。如何保证 nvc.GetValues(k) 不返回 null?
    • @tianxu0836 好电话;我假设一个没有值的键会返回一个空字符串,但猜不出来。
    【解决方案6】:

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

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

    【讨论】:

      【解决方案7】:

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

      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
      

      【讨论】:

        【解决方案8】:

        制作一个使用几个循环的扩展方法。我更喜欢这个解决方案,因为它是可读的(没有 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
        

        【讨论】:

          【解决方案9】:

          这应该可以在没有太多代码的情况下工作:

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

          【讨论】:

            【解决方案10】:

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

            【讨论】:

              【解决方案11】:

              正如@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】:

                这对我有用:

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2019-11-27
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-18
                  • 2010-09-09
                  • 1970-01-01
                  • 2017-03-08
                  • 2023-03-09
                  相关资源
                  最近更新 更多