当从代码中调用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,我没有找到一个,这让我想到了以下问题:
你所知道的最优雅干净的方法是什么?
奇怪的是没有人提到来自asp.net . core的QueryBuilder。
当你有一个重复键的查询,比如?filter=a&filter=b,它会很有用
var qb = new QueryBuilder();
qb.Add("filter", new string[] {"A", "B"});
然后你只需要将qb添加到URI中,它就会自动转换为字符串。
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.extensions.querybuilder?view=aspnetcore-5.0
下面的代码是从ToString的HttpValueCollection实现中截取的,通过ILSpy,它会给你一个name=value querystring。
不幸的是,HttpValueCollection是一个内部类,只有当你使用HttpUtility.ParseQueryString()时才会返回。我删除了它的所有视图状态部分,它默认编码:
public static class HttpExtensions
{
public static string ToQueryString(this NameValueCollection collection)
{
// This is based off the NameValueCollection.ToString() implementation
int count = collection.Count;
if (count == 0)
return string.Empty;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < count; i++)
{
string text = collection.GetKey(i);
text = HttpUtility.UrlEncodeUnicode(text);
string value = (text != null) ? (text + "=") : string.Empty;
string[] values = collection.GetValues(i);
if (stringBuilder.Length > 0)
{
stringBuilder.Append('&');
}
if (values == null || values.Length == 0)
{
stringBuilder.Append(value);
}
else
{
if (values.Length == 1)
{
stringBuilder.Append(value);
string text2 = values[0];
text2 = HttpUtility.UrlEncodeUnicode(text2);
stringBuilder.Append(text2);
}
else
{
for (int j = 0; j < values.Length; j++)
{
if (j > 0)
{
stringBuilder.Append('&');
}
stringBuilder.Append(value);
string text2 = values[j];
text2 = HttpUtility.UrlEncodeUnicode(text2);
stringBuilder.Append(text2);
}
}
}
}
return stringBuilder.ToString();
}
}
HttpValueCollection的可链接包装类:
namespace System.Web.Mvc {
public class QueryStringBuilder {
private NameValueCollection collection;
public QueryStringBuilder() {
collection = System.Web.HttpUtility.ParseQueryString(string.Empty);
}
public QueryStringBuilder Add(string key, string value) {
collection.Add(key, value);
return this;
}
public QueryStringBuilder Remove(string key) {
collection.Remove(key);
return this;
}
public string this[string key] {
get { return collection[key]; }
set { collection[key] = value; }
}
public string ToString() {
return collection.ToString();
}
}
}
使用示例:
QueryStringBuilder parameters = new QueryStringBuilder()
.Add("view", ViewBag.PageView)
.Add("page", ViewBag.PageNumber)
.Add("size", ViewBag.PageSize);
string queryString = parameters.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¶mA=A¶mB=B