Working with QueryStrings, a critique and different solution.

Today I was reading DotNetKicks like I normally do and came across this article in the up and coming section, Parsing query string in ASP.NET safely. I felt the author had quite a bit of conflicting code in his blog post.

I was not a fan of having get properties that had associated private member backing fields but the backing fields weren’t even reliably used. The other issue I had was the fact the int? return property would default to 0 instead of null which overrides the point of using nullables, the last issue I had was the GET properties would cause conversion to be done on the RequestString every time.

private string QueryText
{
    get { return (string) (ViewState["ViewStateQueryText"] ??
 (ViewState["ViewStateQueryText"] = string.Empty)); }
    set { ViewState["ViewStateQueryText"] = value; }
}

private int? QueryId
{
    get { return (int?) (ViewState["ViewStateQueryId"]); }
    set { ViewState["ViewStateQueryText"] = value; }
}

private Guid? QueryGuid
{
    get { return (Guid?) (ViewState["ViewStateQueryGuid"]); }
    set { ViewState["ViewStateQueryGuid"] = value; }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        QueryText = ConverQuerystringToString("QueryText");

        QueryId = ConverQuerystringToInt("QueryId");

        QueryGuid = ConvertQueryStringToGuid("QueryGuid");

        bool hasValue = QueryGuid.HasValue;
        hasValue = QueryId.HasValue;
    }
}

/// <summary>
/// Converts the query string to GUID.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private Guid? ConvertQueryStringToGuid(string key)
{
    if (string.IsNullOrEmpty(Request.QueryString[key]))
        return null;

    try
    {
        return new Guid(Request.QueryString[key]);
    }
    catch
    {
        return null;
    }
}

/// <summary>
/// Convers the querystring to string.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private string ConverQuerystringToString(string key)
{
    return Request.QueryString[key] ?? string.Empty;
}

/// <summary>
/// Convers the querystring to int.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private int? ConverQuerystringToInt(string key)
{
    int tmpParse;
    return int.TryParse(Request.QueryString[key], out tmpParse) ?
tmpParse : (int?) null;
}

This is how I handle reading the query string in my applications. If you’re wondering what’s going on inside the QueryText property I am doing 1 line lazy loading on the ViewState. This takes advantage of the lesser known fact that the assignment operator does not return void but actually returns itself which you can combine with the null coalescing operator to create 1 line lazy loading.

Let me know what you think about my practices. I love nullables for always having .HasValue and .GetValueOrDefault() to handle how I want to deal with defaults. I hate having to pick arbitrary values for default checks like -1 or 0 for ints etc.

UPDATE: 11/12

So I’m going to include a version for us on 3.5 where these methods are in an extension method over the querystring NameValueCollection.

public static class QueryStringExtensions
{
    /// <summary>
    /// Converts the query string to GUID.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static Guid? GetGuid(this NameValueCollection queryString, string key)
    {
        if (string.IsNullOrEmpty(queryString[key]))
            return null;

        try
        {
            return new Guid(queryString[key]);
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// Convers the querystring to string.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static string GetString(this NameValueCollection queryString, string key)
    {
        return queryString[key] ?? string.Empty;
    }

    /// <summary>
    /// Convers the querystring to int.
    /// </summary>
    /// <param name="queryString">The query string.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static int? GetInt(this NameValueCollection queryString, string key)
    {
        int tmpParse;
        return int.TryParse(queryString[key], out tmpParse) ?
tmpParse : (int?) null;
    }
}

Usage example (using same .aspx page as above)

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        QueryText = Request.QueryString.GetString("QueryText");

        QueryId = Request.QueryString.GetInt("QueryId");

        QueryGuid = Request.QueryString.GetGuid("QueryGuid");

        bool hasValue = QueryGuid.HasValue;
        hasValue = QueryId.HasValue;
    }
}

BloggingContext.ApplicationInstance.CompleteRequest();

kick it on DotNetKicks.com

Advertisements