web-dev-qa-db-fra.com

Comment testez-vous vos variables Request.QueryString []?

J'utilise fréquemment Request.QueryString[] variables.

Dans mon Page_load Je fais souvent des choses comme:

       int id = -1;

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

        DoSomethingSpectacularNow(id);

Tout cela semble un peu maladroit et poubelle. Comment gérez-vous votre Request.QueryString[]s?

50
inspite

Vous trouverez ci-dessous une méthode d'extension qui vous permettra d'écrire du code comme celui-ci:

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

Il utilise TypeDescriptor pour effectuer la conversion. Selon vos besoins, vous pouvez ajouter une surcharge qui prend une valeur par défaut au lieu de lever une 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(T)));
    }

    return (T) converter.ConvertFrom(value);
}
52
Bryan Watts

Utilisez plutôt int.TryParse pour vous débarrasser du bloc try-catch:

if (!int.TryParse(Request.QueryString["id"], out id))
{
  // error case
}
34
VVS

Essayez ce mec ...

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

Ensuite, vous pourrez rechercher le gars pour une chaîne très facile via ...

keys.Contains("someKey")
19
AutomationNation

J'utilise une petite méthode d'aide:

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

Cette méthode me permet de lire les valeurs de la chaîne de requête de la manière suivante:

int id = QueryString("id", 0);
17
M4N

Eh bien, pour une chose, utilisez int.TryParse à la place ...

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

Cela suppose que "non présent" devrait avoir le même résultat que "pas un entier" bien sûr.

EDIT: Dans d'autres cas, quand vous allez utiliser des paramètres de requête comme chaînes de toute façon, je pense que c'est certainement une bonne idée de valider leur présence.

10
Jon Skeet

Vous pouvez également utiliser les méthodes d'extension ci-dessous et faire comme ça

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

}

// Méthodes d'extension

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;
}
9
terjetyl
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
4
Colin Dekker

J'ai des fonctions pour chacune (en fait c'est une petite classe, avec beaucoup de statiques):

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

Il retourne -1 en cas d'échec (ce qui est presque toujours OK pour moi, j'ai aussi d'autres fonctions pour les nombres négatifs).

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

Eeee c'est un risque de karma ...

J'ai une DRY abstraction testable par unité car, eh bien, parce qu'il y avait trop de variables de chaîne de requête pour continuer dans une conversion héritée.

Le code ci-dessous provient d'une classe utilitaire dont le constructeur nécessite une entrée NameValueCollection (this.source) et le tableau de chaînes "clés" est dû au fait que l'application héritée était plutôt organique et avait développé la possibilité pour plusieurs chaînes différentes d'être une clé d'entrée potentielle. Cependant j'aime un peu l'extensibilité. Cette méthode inspecte la collection pour la clé et la renvoie dans le type de données requis.

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;
}
1
annakata

J'ai en fait une classe utilitaire qui utilise des génériques pour "boucler" la session, qui fait tout le "travail de grognement" pour moi, j'ai aussi quelque chose presque identique pour travailler avec les valeurs QueryString.

Cela permet de supprimer la dupe de code pour les contrôles (souvent nombreux).

Par exemple:

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");
}

REMARQUE:

Cela utilise évidemment la statique, que certaines personnes n'aiment pas en raison de la façon dont elle peut avoir un impact sur le code de test .. Vous pouvez facilement refactoriser en quelque chose qui fonctionne en fonction des instances et des interfaces dont vous avez besoin .. Je pense simplement que l'exemple de la statique est le plus lumineux.

J'espère que cela aide/donne matière à réflexion.

1
Rob Cooper

J'ai modifié la réponse de Bryan Watts de sorte que si le paramètre que vous demandez n'existe pas et que vous avez spécifié un type nullable, il retournera 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);
    }

Vous pouvez maintenant faire ceci:

Request.QueryString.GetValue<int?>(paramName) ?? 10;
1
W3Max