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?
The code below is taken off the
HttpValueCollection
implementation ofToString
, via ILSpy, which gives you a name=value querystring.Unfortunately HttpValueCollection is an internal class which you only ever get back if you use
HttpUtility.ParseQueryString()
. I removed all the viewstate parts to it, and it encodes by default:Here's my late entry. I didn't like any of the others for various reasons, so I wrote my own.
This version features:
Use of StringBuilder only. No ToArray() calls or other extension methods. It doesn't look as pretty as some of the other responses, but I consider this a core function so efficiency is more important than having "fluent", "one-liner" code which hide inefficiencies.
Handles multiple values per key. (Didn't need it myself but just to silence Mauricio ;)
Example Usage
Output
I went with the solution proposed by DSO (answered on Aug 2 '11 at 7:29), his solution does not require using HttpUtility. However, as per an article posted in Dotnetpearls, using a Dictionary is faster (in performance) than using NameValueCollection. Here is DSO's solution modified to use Dictionary in place of NameValueCollection.
You can create a new writeable instance of
HttpValueCollection
by callingSystem.Web.HttpUtility.ParseQueryString(string.Empty)
, and then use it as anyNameValueCollection
. Once you have added the values you want, you can callToString
on the collection to get a query string, as follows:The
HttpValueCollection
is internal and so you cannot directly construct an instance. However, once you obtain an instance you can use it like any otherNameValueCollection
. Since the actual object you are working with is anHttpValueCollection
, calling ToString method will call the overridden method onHttpValueCollection
, 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/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers
Assuming that you want to reduce dependencies to other assemblies and to keep things simple, you can do:
This works well with loops too. The final ampersand removal needs to go outside of the loop.
Note that the concatenation operator is used to improve readability. The cost of using it compared to the cost of using a StringBuilder is minimal (I think Jeff Atwood posted something on this topic).