How to build a query string for a URL in C#?
A common task when calling web resources from a code is building a query string to including all the necessary parameters. While by all means no rocket science, there are some nifty details you need to take care of like, appending an &
if not the first parameter, encoding the parameters etc.
The code to do it is very simple, but a bit tedious:
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")); }
}
This is such a common task one would expect a utility class to exist that makes it more elegant and readable. Scanning MSDN, I failed to find one—which brings me to the following question:
What is the most elegant clean way you know of doing the above?
If you look under the hood the QueryString property is a NameValueCollection. When I've done similar things I've usually been interested in serialising AND deserialising so my suggestion is to build a NameValueCollection up and then pass to:
using System.Web;
using System.Collections.Specialized;
private string ToQueryString(NameValueCollection nvc)
{
var array = (from key in nvc.AllKeys
from value in nvc.GetValues(key)
select string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)))
.ToArray();
return "?" + string.Join("&", array);
}
Possibly I could've formatted that better :)
I imagine there's a super elegant way to do this in LINQ too...
You can create a new writeable instance of HttpValueCollection
by calling System.Web.HttpUtility.ParseQueryString(string.Empty)
, and then use it as any NameValueCollection
. Once you have added the values you want, you can call ToString
on the collection to get a query string, as follows:
NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
queryString["key1"] = "value1";
queryString["key2"] = "value2";
return queryString.ToString(); // Returns "key1=value1&key2=value2", all URL-encoded
The HttpValueCollection
is internal and so you cannot directly construct an instance. However, once you obtain an instance you can use it like any other NameValueCollection
. Since the actual object you are working with is an HttpValueCollection
, calling ToString method will call the overridden method on HttpValueCollection
, which formats the collection as a URL-encoded query string.
After searching SO and the web for an answer to a similar issue, this is the most simple solution I could find.
.NET Core
If you're working in .NET Core, you can use the Microsoft.AspNetCore.WebUtilities.QueryHelpers
class, which simplifies this greatly.
https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.webutilities.queryhelpers
With the inspiration from Roy Tinker's comment, I ended up using a simple extension method on the Uri class that keeps my code concise and clean:
using System.Web;
public static class HttpExtensions
{
public static Uri AddQuery(this Uri uri, string name, string value)
{
var httpValueCollection = HttpUtility.ParseQueryString(uri.Query);
httpValueCollection.Remove(name);
httpValueCollection.Add(name, value);
var ub = new UriBuilder(uri);
ub.Query = httpValueCollection.ToString();
return ub.Uri;
}
}
Usage:
Uri url = new Uri("http://localhost/rest/something/browse").
AddQuery("page", "0").
AddQuery("pageSize", "200");
Edit - Standards compliant variant
As several people pointed out, httpValueCollection.ToString()
encodes Unicode characters in a non-standards-compliant way. This is a variant of the same extension method that handles such characters by invoking HttpUtility.UrlEncode
method instead of the deprecated HttpUtility.UrlEncodeUnicode
method.
using System.Web;
public static Uri AddQuery(this Uri uri, string name, string value)
{
var httpValueCollection = HttpUtility.ParseQueryString(uri.Query);
httpValueCollection.Remove(name);
httpValueCollection.Add(name, value);
var ub = new UriBuilder(uri);
// this code block is taken from httpValueCollection.ToString() method
// and modified so it encodes strings with HttpUtility.UrlEncode
if (httpValueCollection.Count == 0)
ub.Query = String.Empty;
else
{
var sb = new StringBuilder();
for (int i = 0; i < httpValueCollection.Count; i++)
{
string text = httpValueCollection.GetKey(i);
{
text = HttpUtility.UrlEncode(text);
string val = (text != null) ? (text + "=") : string.Empty;
string[] vals = httpValueCollection.GetValues(i);
if (sb.Length > 0)
sb.Append('&');
if (vals == null || vals.Length == 0)
sb.Append(val);
else
{
if (vals.Length == 1)
{
sb.Append(val);
sb.Append(HttpUtility.UrlEncode(vals[0]));
}
else
{
for (int j = 0; j < vals.Length; j++)
{
if (j > 0)
sb.Append('&');
sb.Append(val);
sb.Append(HttpUtility.UrlEncode(vals[j]));
}
}
}
}
}
ub.Query = sb.ToString();
}
return ub.Uri;
}
链接地址: http://www.djcxy.com/p/26514.html
上一篇: 我应该使用encodeURI还是encodeURIComponent来编码URL?
下一篇: 如何在C#中为URL创建查询字符串?