当从代码中调用web资源时,一个常见的任务是构建一个包含所有必要参数的查询字符串。虽然这绝不是火箭科学,但有一些漂亮的细节需要注意,例如,如果不是第一个参数,则添加&,对参数进行编码等。

实现它的代码非常简单,但有点乏味:

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

这是一个非常常见的任务,人们希望存在一个实用工具类,使其更加优雅和可读。扫描MSDN,我没有找到一个,这让我想到了以下问题:

你所知道的最优雅干净的方法是什么?


当前回答

public string UrlQueryStr(object data)
{
    if (data == null)
        return string.Empty;

    object val;
    StringBuilder sb = new StringBuilder();

    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(data))
    {
        if ((val = prop.GetValue(data)) != null)
        {
            sb.AppendFormat("{0}{1}={2}", sb.Length == 0 ? '?' : '&',
                HttpUtility.UrlEncode(prop.Name), HttpUtility.UrlEncode(val.ToString()));
        }
    }
    return sb.ToString();
}

其他回答

我刚才回答了一个类似的问题。基本上,最好的方法是使用HttpValueCollection类。净的请求。QueryString属性实际上是,不幸的是,它是。net框架内部的。 您可以使用Reflector来抓取它(并将其放入您的Utils类中)。通过这种方式,您可以像操作NameValueCollection一样操作查询字符串,但是需要考虑所有url编码/解码问题。

HttpValueCollection扩展了NameValueCollection,并有一个接受编码查询字符串(包括&和问号)的构造函数,它覆盖了ToString()方法,以便稍后从底层集合重新构建查询字符串。

例子:

  var coll = new HttpValueCollection();

  coll["userId"] = "50";
  coll["paramA"] = "A";
  coll["paramB"] = "B";      

  string query = coll.ToString(true); // true means use urlencode

  Console.WriteLine(query); // prints: userId=50&paramA=A&paramB=B

如何创建扩展方法,允许您以这样流畅的风格添加参数?

string a = "http://www.somedomain.com/somepage.html"
    .AddQueryParam("A", "TheValueOfA")
    .AddQueryParam("B", "TheValueOfB")
    .AddQueryParam("Z", "TheValueOfZ");

string b = new StringBuilder("http://www.somedomain.com/anotherpage.html")
    .AddQueryParam("A", "TheValueOfA")
    .AddQueryParam("B", "TheValueOfB")
    .AddQueryParam("Z", "TheValueOfZ")
    .ToString(); 

下面是使用字符串的重载:

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

    return source + delim + HttpUtility.UrlEncode(key)
        + "=" + HttpUtility.UrlEncode(value);
}

这里是使用StringBuilder的重载:

public static StringBuilder AddQueryParam(
    this StringBuilder source, string key, string 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));
}

我将以下方法添加到PageBase类中。

protected void Redirect(string url)
    {
        Response.Redirect(url);
    }
protected void Redirect(string url, NameValueCollection querystrings)
    {
        StringBuilder redirectUrl = new StringBuilder(url);

        if (querystrings != 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());
    }

电话:

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

下面是一个使用非常基本的语言特性的实现。它是我们必须在Objective C中移植和维护的类的一部分,所以我们选择了更多的代码行,但更容易移植和理解不太熟悉c#的程序员。

        /// <summary>
        /// Builds a complete http url with query strings.
        /// </summary>
        /// <param name="pHostname"></param>
        /// <param name="pPort"></param>
        /// <param name="pPage">ex "/index.html" or index.html</param>
        /// <param name="pGetParams">a Dictionary<string,string> collection containing the key value pairs.  Pass null if there are none.</param>
        /// <returns>a string of the form: http://[pHostname]:[pPort/[pPage]?key1=val1&key2=val2...</returns>

  static public string buildURL(string pHostname, int pPort, string pPage, Dictionary<string,string> pGetParams)
        {
            StringBuilder sb = new StringBuilder(200);
            sb.Append("http://");
            sb.Append(pHostname);
            if( pPort != 80 ) {
                sb.Append(pPort);
            }
            // Allows page param to be passed in with or without leading slash.
            if( !pPage.StartsWith("/") ) {
                sb.Append("/");
            }
            sb.Append(pPage);

            if (pGetParams != null && pGetParams.Count > 0)
            {
                sb.Append("?");
                foreach (KeyValuePair<string, string> kvp in pGetParams)
                {
                    sb.Append(kvp.Key);
                    sb.Append("=");
                    sb.Append( System.Web.HttpUtility.UrlEncode(kvp.Value) );
                    sb.Append("&");
                }
                sb.Remove(sb.Length - 1, 1); // Remove the final '&'
            }
            return sb.ToString();
        }

查询字符串可以通过以下方式添加到URL:

创建名称值集合对象 将查询字符串项及其值添加到此对象 将此名称值集合对象编码为下面链接中提供的代码的url

https://blog.codingnovice.com/blog

public ActionResult Create()
{
    //declaring name value collection object
    NameValueCollection collection = new NameValueCollection();

    //adding new value to the name value collection object
    collection.Add("Id1", "wwe323");
    collection.Add("Id2", "454w");
    collection.Add("Id3", "tyt5656");
    collection.Add("Id4", "343wdsd");

    //generating query string
    string url = GenerateQueryString(collection);

    return View();
}

private string GenerateQueryString(NameValueCollection collection)
{
    var querystring = (
        from key in collection.AllKeys
        from value in collection.GetValues(key)
        select string.Format("{0}={1}",
            HttpUtility.UrlEncode(key),
            HttpUtility.UrlEncode(value))
    ).ToArray();
    return "?" + string.Join("&", querystring);
}