Sunday, February 8, 2009

Query String Utilities

Every time I write any web layer code, I always end up have to manipulate query strings and this little class pays dividends when manipulating the Query String

Uri mainUrl = . . . 
QueryStringCollection queryString = new QueryStringCollection(mainUrl.Query);
queryString.Add("BookingEventId", bookingEventId.ToString());

So here is the class, it has indexers, contains, to strings and will automatically Url encode.

/// <summary>
///
A chainable query string helper class.
/// </summary>
/// <example>
///
string strQuery = QueryString.Current.Add("id", "179").ToString();
/// string strQuery = new QueryString().Add("id", "179").ToString();
/// </example>
[SuppressMessage("Microsoft.Design", "CA1035:ICollectionImplementationsHaveStronglyTypedMembers",
Justification="We are implementing a new object based collection."), Serializable]
public class QueryStringCollection : NameValueCollection
{
public QueryStringCollection() { }

/// <summary>
///
Initializes a new instance of the <see cref="QueryStringCollection"/> class.
/// </summary>
/// <param name="info">
A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object that contains the information required to serialize the new <see cref="T:System.Collections.Specialized.NameValueCollection"/> instance.</param>
/// <param name="context">
A <see cref="T:System.Runtime.Serialization.StreamingContext"/> object that contains the source and destination of the serialized stream associated with the new <see cref="T:System.Collections.Specialized.NameValueCollection"/> instance.</param>
protected QueryStringCollection(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}

/// <summary>
///
Initializes a new instance of the <see cref="QueryStringCollection"/> class.
/// </summary>
/// <param name="queryString">
The query string.</param>
public QueryStringCollection(string queryString)
{
FillFromString(queryString);
}

/// <summary>
///
Gets the current.
/// </summary>
/// <value>
The current.</value>
public static QueryStringCollection Current
{
get
{
return new QueryStringCollection().FromCurrent();
}
}

/// <summary>
///
Extracts the query string.
/// </summary>
/// <param name="value">
The value.</param>
/// <returns></returns>
public static string ExtractQueryString(string value)
{
if (!string.IsNullOrEmpty(value))
{
if (value.Contains("?"))
return value.Substring(value.IndexOf("?", StringComparison.OrdinalIgnoreCase) + 1);
}
return value;
}

/// <summary>
///
Fills from string.
/// </summary>
/// <param name="value">
The value.</param>
/// <returns></returns>
public QueryStringCollection FillFromString(string value)
{
base.Clear();
if (string.IsNullOrEmpty(value)) return this;
foreach (string keyValuePair in ExtractQueryString(value).Split('&'))
{
if (string.IsNullOrEmpty(keyValuePair)) continue;
string[] split = keyValuePair.Split('=');
base.Add(split[0],
split.Length == 2 ? split[1] : "");
}
return this;
}

/// <summary>
///
returns a QueryString object based on the current querystring of the request
/// </summary>
/// <returns>
the QueryString object </returns>
public QueryStringCollection FromCurrent()
{
if (HttpContext.Current != null)
{
return FillFromString(HttpContext.Current.Request.QueryString.ToString());
}
base.Clear();
return this;
}

/// <summary>
///
add a name value pair to the collection
/// </summary>
/// <param name="name">
the name</param>
/// <param name="value">
the value associated to the name</param>
/// <returns>
the QueryString object </returns>
public new QueryStringCollection Add(string name, string value)
{
return Add(name, value, false);
}

/// <summary>
///
adds a name value pair to the collection
/// </summary>
/// <param name="name">
the name</param>
/// <param name="value">
the value associated to the name</param>
/// <param name="isUnique">
true if the name is unique within the querystring. This allows us to override existing values</param>
/// <returns>
the QueryString object </returns>
public QueryStringCollection Add(string name, string value, bool isUnique)
{
string existingValue = base[name];
if (string.IsNullOrEmpty(existingValue))
base.Add(name, HttpUtility.UrlEncodeUnicode(value));
else if (isUnique)
base[name] = HttpUtility.UrlEncodeUnicode(value);
else
base
[name] += "," + HttpUtility.UrlEncodeUnicode(value);
return this;
}

/// <summary>
///
removes a name value pair from the querystring collection
/// </summary>
/// <param name="name">
name of the querystring value to remove</param>
/// <returns>
the QueryString object</returns>
public new QueryStringCollection Remove(string name)
{
string existingValue = base[name];
if (!string.IsNullOrEmpty(existingValue))
base.Remove(name);
return this;
}

/// <summary>
///
clears the collection
/// </summary>
/// <returns>
the QueryString object </returns>
public QueryStringCollection Reset()
{
base.Clear();
return this;
}

/// <summary>
///
Encrypts the keys and values of the entire querystring acc. to a key you specify
/// </summary>
/// <returns>
an encrypted querystring object</returns>
public QueryStringCollection Encrypt()
{
QueryStringCollection qs = new QueryStringCollection();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
qs.Add(base.Keys[i].Encrypt(), HttpUtility.UrlDecode(val).Encrypt());
}
}
return qs;
}

/// <summary>
///
Decrypts the keys and values of the entire querystring acc. to a key you specify
/// </summary>
/// <returns>
a decrypted querystring object</returns>
public QueryStringCollection Decrypt()
{
QueryStringCollection qs = new QueryStringCollection();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
qs.Add(HttpUtility.UrlDecode(base.Keys[i]).Decrypt(), HttpUtility.UrlDecode(val).Decrypt());
}
}
return qs;
}

/// <summary>
///
overrides the default
/// </summary>
/// <param name="name"></param>
/// <returns>
the associated decoded value for the specified name</returns>
public new string this[string name]
{
get
{
return HttpUtility.UrlDecode(base[name]);
}
}

/// <summary>
///
overrides the default indexer
/// </summary>
/// <param name="index"></param>
/// <returns>
the associated decoded value for the specified index</returns>
public new string this[int index]
{
get
{
return HttpUtility.UrlDecode(base[index]);
}
}

/// <summary>
///
checks if a name already exists within the query string collection
/// </summary>
/// <param name="name">
the name to check</param>
/// <returns>
a boolean if the name exists</returns>
public bool Contains(string name)
{
string existingValue = base[name];
return !string.IsNullOrEmpty(existingValue);
}

/// <summary>
///
outputs the querystring object to a string
/// </summary>
/// <returns>
the encoded querystring as it would appear in a browser</returns>
public override string ToString()
{
StringBuilder builder = new StringBuilder();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
builder.Append((builder.Length == 0) ? "?" : "&").Append(HttpUtility.UrlEncodeUnicode(base.Keys[i])).Append("=").Append(val);
}
}
return builder.ToString();
}
}

No comments: