Over the years, all the way back to the ASP 2.0 days, elegantly handling the Query String parameters between gets has been a challenge. With Web Forms for ASP.NET View State put this issue on the backburner, but with MVC on the rise and restful applications becoming hot, Query String parameters have come back to the forefront.
For an example of where the Query String parameters can get cumbersome, consider a web page which lists products. At the least the page would have paging support, most sites with paging by query string parameters (something like "?page=1"). Now add to the navigation sorting and custom filtering. Depending on the complexity of the sorting you can easily have Query Strings starting to look like "?page=1&sort_col=name&dir=asc&filterby=desc&filter=custom%20filter". While the Query String itself is not complex, the dynamic nature of it can become cumbersome and blotted within the code. Who wants to write the series of conditionals building the custom expression (for each link)? I certainly don't do it; the process is too mechanical for my taste.
To solve this, I explored using an Extension Method upon NameValueCollection, the type for Request.QueryString. Doing this allowed for a pipe like syntax best demonstrated with an example.
Note what is occurring in the code above. The original query string is being conditionally appended or updated based upon some inline form validation. To me the syntax is much cleaner and presents less bloat than a few conditionals for each field (does the field exist? Should I add it or update it? Etc).
Please feel free to grab a copy of the extension methods here, just let me know if you have any feedback!
using System;
using System.Collections.Specialized;
using System.Text;
namespace CustomExtension
{
public static class Extensions
{
public static string WriteLocalPathWithQuery(
this NameValueCollection collection, Uri Url)
{
if (collection.Count == 0)
return Url.LocalPath;
StringBuilder sb = new StringBuilder(Url.LocalPath);
sb.Append("?");
for (int i = 0; i < collection.Keys.Count; i++)
{
if (i != 0)
sb.Append("&");
sb.Append(
String.Format("{0}={1}",
collection.Keys[i], collection[i])
);
}
return sb.ToString();
}
public static NameValueCollection ChangeField(this NameValueCollection collection,
string Key, string Value)
{
return ChangeField(collection, Key, Value, true);
}
public static NameValueCollection ChangeField(this NameValueCollection collection,
string Key, string Value, bool Allow)
{
if (Allow)
{
if (!String.IsNullOrEmpty(collection[Key]))
collection[Key] = Value;
else
collection.Add(Key, Value);
}
else //remove the value all together
{
if (!String.IsNullOrEmpty(collection[Key]))
collection.Remove(Key);
}
return collection;
}
public static NameValueCollection Duplicate(this NameValueCollection source)
{
NameValueCollection collection = new NameValueCollection();
foreach (string key in source)
collection.Add(key, source[key]);
return collection;
}
}
}