views:

5644

answers:

11

I frequently make use of Request.QueryString[] variables.

In my Page_load I often do things like:

       int id = -1;

        if (Request.QueryString["id"] != null) {
            try
            {
                id = int.Parse(Request.QueryString["id"]);
            }
            catch
            {
                // deal with it
            }
        }

        DoSomethingSpectacularNow(id);

It all seems a bit clunky and rubbish, how do you deal with your Request.QueryString[]s?

+7  A: 

Use int.TryParse instead to get rid of the try-catch block:

if (!int.TryParse(Request.QueryString["id"], out id))
{
  // error case
}
VVS
Thanks buddy, that's the kind of tip I needed :D
DrG
Yeah, TryParse is great!
Yadyn
+3  A: 

Well for one thing use int.TryParse instead...

int id;
if (!int.TryParse(Request.QueryString["id"], out id))
{
    id = -1;
}

That assumes that "not present" should have the same result as "not an integer" of course.

EDIT: In other cases, when you're going to use request parameters as strings anyway, I think it's definitely a good idea to validate that they're present.

Jon Skeet
+1  A: 

if(!string.IsNullOrEmpty(Request.QueryString["id"]) { .... }

+1  A: 

I do have functions for each (actually it's one small class, with lots of statics) :

  • GetIntegerFromQuerystring(val)
  • GetIntegerFromPost(val)
  • ....

It returns -1 if fails (which is almost always OK for me, , I have some other functions for negative numbers as well.)

Dim X as Integer = GetIntegerFromQuerystring("id")
If x = -1 Then Exit Sub
dr. evil
+10  A: 

I'm using a little helper method:

public static int QueryString(string paramName, int defaultValue)
{
    int value;
    if (!int.TryParse(Request.QueryString[paramName], out value))
     return defaultValue;
    return value;
}

This method allows me to read values from the query string in the following way:

int id = QueryString("id", 0);
M4N
What a great idea for a helper method to put in a class library!
Mitchel Sellers
Yes I like it too ;D
DrG
In fact there's an error inside the method. Instead of "Request.QueryString" it should be "HttpContext.Current.Request.QueryString".
M4N
+1  A: 

Eeee this is a karma risk...

I have a DRY unit-testable abstraction because, well, because there were too many querystring variables to keep on in a legacy conversion.

The code below is from a utility class whose constructor requires a NameValueCollection input (this.source) and the string array "keys" is because the legacy app was rather organic and had developed the possibility for several different strings to be a potential input key. However I kind of like the extensibility. This method inspects the collection for the key and returns it in the datatype required.

private T GetValue<T>(string[] keys)
{
    return GetValue<T>(keys, default(T));
}

private T GetValue<T>(string[] keys, T vDefault)
{
    T x = vDefault;

    string v = null;

    for (int i = 0; i < keys.Length && String.IsNullOrEmpty(v); i++)
    {
     v = this.source[keys[i]];
    }

    if (!String.IsNullOrEmpty(v))
    {
     try
     {
      x = (typeof(T).IsSubclassOf(typeof(Enum))) ? (T)Enum.Parse(typeof(T), v) : (T)Convert.ChangeType(v, typeof(T));
     }
     catch(Exception e)
     {
      //do whatever you want here
     }
    }

    return x;
}
annakata
This is pretty much the same as what I use.. :)
Rob Cooper
+1  A: 

I actually have a utility class that uses Generics to "wrap" session, which does all of the "grunt work" for me, I also have something almost identical for working with QueryString values.

This helps remove the code dupe for the (often numerous) checks..

For example:

public class QueryString
{
    static NameValueCollection QS
    {
        get
        {
            if (HttpContext.Current == null)
                throw new ApplicationException("No HttpContext!");

            return HttpContext.Current.Request.QueryString;
        }
    }

    public static int Int(string key)
    {
        int i; 
        if (!int.TryParse(QS[key], out i))
            i = -1; // Obviously Change as you see fit.
        return i;
    }

    // ... Other types omitted.
}

// And to Use..
void Test()
{
    int i = QueryString.Int("test");
}

NOTE:

This obviously makes use of statics, which some people don't like because of the way it can impact test code.. You can easily refactor into something that works based on instances and any interfaces you require.. I just think the statics example is the lightest.

Hope this helps/gives food for thought.

Rob Cooper
+6  A: 

You can use the extension methods below as well and do like this

int? id = Request["id"].ToInt();
if(id.HasValue)
{

}

// Extension methods

public static int? ToInt(this string input) 
{
    int val;
    if (int.TryParse(input, out val))
        return val;
    return null;
}

public static DateTime? ToDate(this string input)
{
    DateTime val;
    if (DateTime.TryParse(input, out val))
        return val;
    return null;
}

public static decimal? ToDecimal(this string input)
{
    decimal val;
    if (decimal.TryParse(input, out val))
        return val;
    return null;
}
TT
This is pretty smart I like it. Thanks
DrG
+14  A: 

Below is an extension method that will allow you to write code like this:

int id = request.QueryString.GetValue<int>("id");
DateTime date = request.QueryString.GetValue<DateTime>("date");

It makes use of TypeDescriptor to perform the conversion. Based on your needs, you could add an overload which takes a default value instead of throwing an exception:

public static T GetValue<T>(this NameValueCollection collection, string key)
{
    if(collection == null)
    {
        throw new ArgumentNullException("collection");
    }

    var value = collection[key];

    if(value == null)
    {
        throw new ArgumentOutOfRangeException("key");
    }

    var converter = TypeDescriptor.GetConverter(typeof(T));

    if(!converter.CanConvertFrom(typeof(string)))
    {
        throw new ArgumentException(String.Format("Cannot convert '{0}' to {1}", value, typeof(string)));
    }

    return (T) converter.ConvertFrom(value);
}
Bryan Watts
I had to change line 15 and 17 to made this work : var converter = TypeDescriptor.GetConverter(typeof(T)); if (!converter.CanConvertTo(value.GetType()))
lucian.jp
Thank you Bryan
Barbaros Alp
Hi, thats pretty nice however it doesn't work with nullables, e.g int? There may be a bug in type converter? Worth testing if you are interested.
bplus
I am using this code right now in a project, and we have `Request.QueryString.GetValue<int?>("someValue")` in many places and it works just fine. Is that syntax what you meant?
Bryan Watts
A: 

I modified Bryan Watts' answer so that if the param your asking does not exist and you have specified a nullable type it will return null :

public static T GetValue<T>(this NameValueCollection collection, string key)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            var value = collection[key];
            var type = typeof(T);

            if (value == null)
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    return default(T);

                throw new ArgumentOutOfRangeException("key");
            }

            var converter = TypeDescriptor.GetConverter(type);

            if (!converter.CanConvertTo(value.GetType()))
            {
                throw new ArgumentException(String.Format("Cannot convert '{0}' to {1}", value, type));
            }

            return (T)converter.ConvertTo(value, type);
        }

You can now do this :

Request.QueryString.GetValue<int?>(paramName) ?? 10;
W3Max
'Int32Converter' is unable to convert 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
Soonts
+2  A: 

Try this dude...

List<string> keys = new List<string>(Request.QueryString.AllKeys);

Then you will be able to search the guy for a string real easy via...

keys.Contains("someKey")
AutomationNation
Whoa. Yes. Fantastic. +1
routeNpingme