当从代码中调用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,我没有找到一个,这让我想到了以下问题:
你所知道的最优雅干净的方法是什么?
下面是一个使用非常基本的语言特性的实现。它是我们必须在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);
}
虽然不够优雅,但我选择了一个更简单的版本,它不使用NameValueCollecitons——只是一个包装在StringBuilder周围的构建器模式。
public class UrlBuilder
{
#region Variables / Properties
private readonly StringBuilder _builder;
#endregion Variables / Properties
#region Constructor
public UrlBuilder(string urlBase)
{
_builder = new StringBuilder(urlBase);
}
#endregion Constructor
#region Methods
public UrlBuilder AppendParameter(string paramName, string value)
{
if (_builder.ToString().Contains("?"))
_builder.Append("&");
else
_builder.Append("?");
_builder.Append(HttpUtility.UrlEncode(paramName));
_builder.Append("=");
_builder.Append(HttpUtility.UrlEncode(value));
return this;
}
public override string ToString()
{
return _builder.ToString();
}
#endregion Methods
}
根据现有的答案,我确保使用HttpUtility。UrlEncode调用。它是这样使用的:
string url = new UrlBuilder("http://www.somedomain.com/")
.AppendParameter("a", "true")
.AppendParameter("b", "muffin")
.AppendParameter("c", "muffin button")
.ToString();
// Result: http://www.somedomain.com?a=true&b=muffin&c=muffin%20button
基于扩展方法的快速版本:
class Program
{
static void Main(string[] args)
{
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("A", "AValue"),
new KeyValuePair<string, string>("B", "BValue")
};
string output = "?" + string.Join("&", parameters.ConvertAll(param => param.ToQueryString()).ToArray());
}
}
public static class KeyValueExtensions
{
public static string ToQueryString(this KeyValuePair<string, string> obj)
{
return obj.Key + "=" + HttpUtility.UrlEncode(obj.Value);
}
}
可以使用where子句来选择将哪些参数添加到字符串中。
public static string ToQueryString(this Dictionary<string, string> source)
{
return String.Join("&", source.Select(kvp => String.Format("{0}={1}", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value))).ToArray());
}
public static string ToQueryString(this NameValueCollection source)
{
return String.Join("&", source.Cast<string>().Select(key => String.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(source[key]))).ToArray());
}