当从代码中调用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,我没有找到一个,这让我想到了以下问题:
你所知道的最优雅干净的方法是什么?
将这个类添加到项目中
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class QueryStringBuilder
{
private readonly List<KeyValuePair<string, object>> _list;
public QueryStringBuilder()
{
_list = new List<KeyValuePair<string, object>>();
}
public void Add(string name, object value)
{
_list.Add(new KeyValuePair<string, object>(name, value));
}
public override string ToString()
{
return String.Join("&", _list.Select(kvp => String.Concat(Uri.EscapeDataString(kvp.Key), "=", Uri.EscapeDataString(kvp.Value.ToString()))));
}
}
像这样使用它:
var actual = new QueryStringBuilder {
{"foo", 123},
{"bar", "val31"},
{"bar", "val32"}
};
actual.Add("a+b", "c+d");
actual.ToString(); // "foo=123&bar=val31&bar=val32&a%2bb=c%2bd"
另一种方法是创建一个类NameValueCollection的扩展,返回完整的Url:
public static class CustomMethods
{
public static string ToUrl(this System.Collections.Specialized.NameValueCollection collection)
{
if (collection.Count == 0) return "";
string completeUrl = "?";
for (int i = 0; i < collection.Count; i++)
{
completeUrl += new Page().Server.UrlEncode(collection.GetKey(i)) + "=" + new Page().Server.UrlEncode(collection.Get(i));
if ((i + 1) < collection.Count) completeUrl += "&";
}
return completeUrl;
}
}
然后,你可以使用你的新方法,例如:
System.Collections.Specialized.NameValueCollection qString = new System.Collections.Specialized.NameValueCollection();
qString.Add("name", "MyName");
qString.Add("email", "myemail@test.com");
qString.ToUrl(); //Result: "?name=MyName&email=myemail%40test.com"
我写了一些扩展方法,我发现在使用QueryStrings时非常有用。通常我想从当前的QueryString开始,并在使用它之前进行修改。类似的,
var res = Request.QueryString.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
欲了解更多信息,请访问:http://www.charlesrcook.com/archive/2008/07/23/c-extension-methods-for-asp.net-query-string-operations.aspx
很简单,但我喜欢这种风格。
我刚才回答了一个类似的问题。基本上,最好的方法是使用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¶mA=A¶mB=B
只针对那些需要VB的人。NET版本的顶级答案:
Public Function ToQueryString(nvc As System.Collections.Specialized.NameValueCollection) As String
Dim array As String() = nvc.AllKeys.SelectMany(Function(key As String) nvc.GetValues(key), Function(key As String, value As String) String.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(key), System.Web.HttpUtility.UrlEncode(value))).ToArray()
Return "?" + String.Join("&", array)
End Function
以及没有LINQ的版本:
Public Function ToQueryString(nvc As System.Collections.Specialized.NameValueCollection) As String
Dim lsParams As New List(Of String)()
For Each strKey As String In nvc.AllKeys
Dim astrValue As String() = nvc.GetValues(strKey)
For Each strValue As String In astrValue
lsParams.Add(String.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue)))
Next ' Next strValue
Next ' strKey
Dim astrParams As String() = lsParams.ToArray()
lsParams.Clear()
lsParams = Nothing
Return "?" + String.Join("&", astrParams)
End Function ' ToQueryString
和没有LINQ的c#版本:
public static string ToQueryString(System.Collections.Specialized.NameValueCollection nvc)
{
List<string> lsParams = new List<string>();
foreach (string strKey in nvc.AllKeys)
{
string[] astrValue = nvc.GetValues(strKey);
foreach (string strValue in astrValue)
{
lsParams.Add(string.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue)));
} // Next strValue
} // Next strKey
string[] astrParams =lsParams.ToArray();
lsParams.Clear();
lsParams = null;
return "?" + string.Join("&", astrParams);
} // End Function ToQueryString