Como você testar seus [] variáveis ??Request.QueryString?
-
20-08-2019 - |
Pergunta
Eu frequentemente fazem uso de variáveis ??Request.QueryString[]
.
Na minha Page_load
Costumo fazer coisas como:
int id = -1;
if (Request.QueryString["id"] != null) {
try
{
id = int.Parse(Request.QueryString["id"]);
}
catch
{
// deal with it
}
}
DoSomethingSpectacularNow(id);
Tudo parece um desajeitado pouco e lixo. Como você lida com seus Request.QueryString[]
s?
Solução
A seguir é um método de extensão que permitirá que você para escrever código como este:
int id = request.QueryString.GetValue<int>("id");
DateTime date = request.QueryString.GetValue<DateTime>("date");
Ele faz uso de TypeDescriptor
para realizar a conversão. Com base em suas necessidades, você pode adicionar uma sobrecarga que tem um valor padrão em vez de lançar uma exceção:
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(T)));
}
return (T) converter.ConvertFrom(value);
}
Outras dicas
Use int.TryParse em vez de se livrar do bloco try-catch:
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}
Tente este cara ...
List<string> keys = new List<string>(Request.QueryString.AllKeys);
Em seguida, você será capaz de pesquisar na cara por uma corda fácil real via ...
keys.Contains("someKey")
Eu estou usando um método auxiliar pouco:
public static int QueryString(string paramName, int defaultValue)
{
int value;
if (!int.TryParse(Request.QueryString[paramName], out value))
return defaultValue;
return value;
}
Este método permite-me para ler os valores da string de consulta da seguinte maneira:
int id = QueryString("id", 0);
Bem para uma utilização coisa int.TryParse vez ...
int id;
if (!int.TryParse(Request.QueryString["id"], out id))
{
id = -1;
}
Isso pressupõe que "não presente" deve ter o mesmo resultado como "não um inteiro", é claro.
EDIT: Em outros casos, quando você está indo para parâmetros de solicitação usar como cordas de qualquer maneira, eu acho que é definitivamente uma boa idéia para validar que eles estão presentes
.Você pode usar os métodos de extensão abaixo bem e fazer como este
int? id = Request["id"].ToInt();
if(id.HasValue)
{
}
// Os métodos de extensão
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
}
Eeee este é um risco karma ...
Eu tenho uma abstração DRY unidade testável porque, bem, porque havia muitas variáveis ??querystring para manter em em uma conversão de legado.
O código abaixo é de uma classe de utilitário cujo construtor requer uma entrada NameValueCollection (this.source) e as "chaves" matriz de cadeia é porque o aplicativo legado foi bastante orgânica e tinha desenvolvido a possibilidade de várias cordas diferentes para ser um potencial chave de entrada. tipo no entanto I de como a extensibilidade. Este método inspeciona a coleção para a chave e devolve-lo no tipo de dados necessários.
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;
}
Na verdade, tenho uma classe de utilitário que usa genéricos para sessão "envoltório", que faz todo o "trabalho pesado" para mim, eu também tenho algo quase idêntico para trabalhar com valores de QueryString.
Isso ajuda a remover o dupe código para as (muitas vezes numerosos) verifica ..
Por exemplo:
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");
}
NOTA:
Isto, obviamente, faz uso da estática, que algumas pessoas não gostam por causa da forma como ele pode afetar o código de teste .. Você pode facilmente refactor em algo que funciona com base em instâncias e quaisquer interfaces que você precisa .. Eu só acho que o estática exemplo é o mais leve.
Espero que isso ajude / dá o que pensar.
Eu tenho funções para cada um (na verdade, é uma pequena classe, com muita estática):
-
GetIntegerFromQuerystring(val)
-
GetIntegerFromPost(val)
-
....
Ele retorna -1 se falhar ( que é quase sempre OK para mim, eu tenho algumas outras funções para números negativos também ).
Dim X as Integer = GetIntegerFromQuerystring("id")
If x = -1 Then Exit Sub
Eu modifiquei resposta Bryan Watts' para que se o param a sua pergunta não existe e que você tenha especificado um tipo anulável ele irá retornar nulo:
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);
}
Agora você pode fazer isso:
Request.QueryString.GetValue<int?>(paramName) ?? 10;