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?
This question is related to
c#
coding-style
tryparse
isnumeric
request.querystring
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);
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;
}
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.
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;
}
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
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")
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);
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;
}
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")
Use int.TryParse instead to get rid of the try-catch block:
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}
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.
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;
}
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
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.
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)
{
return default(T);
}
var value = collection[key];
if (value == null)
{
return default(T);
}
var type = typeof(T);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = Nullable.GetUnderlyingType(type);
}
var converter = TypeDescriptor.GetConverter(type);
if (!converter.CanConvertTo(value.GetType()))
{
return default(T);
}
return (T)converter.ConvertTo(value, type);
}
You can now do this :
Request.QueryString.GetValue<int?>(paramName) ?? 10;
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;
}
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;
}
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
Use int.TryParse instead to get rid of the try-catch block:
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}
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.
Use int.TryParse instead to get rid of the try-catch block:
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
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.
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.
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
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;
}
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.
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);
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
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)
{
return default(T);
}
var value = collection[key];
if (value == null)
{
return default(T);
}
var type = typeof(T);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = Nullable.GetUnderlyingType(type);
}
var converter = TypeDescriptor.GetConverter(type);
if (!converter.CanConvertTo(value.GetType()))
{
return default(T);
}
return (T)converter.ConvertTo(value, type);
}
You can now do this :
Request.QueryString.GetValue<int?>(paramName) ?? 10;
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);
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
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.
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
Source: Stackoverflow.com