Domanda

Uso spesso Request.QueryString[] variabili.

Nel mio Page_load faccio spesso cose come:

       int id = -1;

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

        DoSomethingSpectacularNow(id);

Sembra tutto un po 'goffo e spazzatura. Come gestisci le tue <=> s?

È stato utile?

Soluzione

Di seguito è riportato un metodo di estensione che ti permetterà di scrivere codice in questo modo:

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

Utilizza TypeDescriptor per eseguire la conversione. In base alle tue esigenze, potresti aggiungere un sovraccarico che assume un valore predefinito invece di generare un'eccezione:

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

Altri suggerimenti

Usa invece int. TryParse per sbarazzarti del blocco try-catch:

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

Prova questo tizio ...

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

Quindi sarai in grado di cercare il tipo di una stringa molto facilmente tramite ...

keys.Contains("someKey")

Sto usando un piccolo metodo di supporto:

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

Questo metodo mi consente di leggere i valori dalla stringa di query nel modo seguente:

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

Beh, per prima cosa usa int. TryParse invece ...

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

Ciò presuppone che " non presente " dovrebbe avere lo stesso risultato di " non un numero intero " ovviamente.

EDIT: in altri casi, quando userete comunque i parametri di richiesta come stringhe, penso che sia sicuramente una buona idea convalidare che siano presenti.

Puoi usare anche i seguenti metodi di estensione e fare così

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

}

// Metodi di estensione

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
}

Ecco, questo è un rischio di karma ...

Ho un'astrazione DRY unit-testable perché, beh, perché c'erano troppe variabili di querystring da mantenere in una conversione legacy.

Il codice seguente proviene da una classe di utilità il cui costruttore richiede un input NameValueCollection (this.source) e l'array di stringhe " keys " è perché l'app legacy era piuttosto organica e aveva sviluppato la possibilità per diverse stringhe diverse di essere una potenziale chiave di input. Comunque mi piace un po 'l'estensibilità. Questo metodo controlla la raccolta per la chiave e la restituisce nel tipo di dati richiesto.

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

In realtà ho una classe di utilità che usa Generics per " wrap " sessione, che fa tutto il " grunt work " per me, ho anche qualcosa di quasi identico per lavorare con i valori di QueryString.

Questo aiuta a rimuovere il codice duplicato per i (spesso numerosi) controlli ..

Ad esempio:

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:

Questo ovviamente fa uso della statica, che ad alcune persone non piace a causa del modo in cui può avere un impatto sul codice di test. Puoi facilmente fare il refactoring in qualcosa che funziona in base alle istanze e alle interfacce di cui hai bisogno. Penso solo che il l'esempio statico è il più leggero.

Spero che questo aiuti / dia spunti di riflessione.

Ho delle funzioni per ciascuna (in realtà è una piccola classe, con molte statistiche):

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

Restituisce -1 se fallisce ( che è quasi sempre OK per me, ho anche altre funzioni per i numeri negativi ).

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

Ho modificato la risposta di Bryan Watts in modo che se il parametro richiesto non esiste e hai specificato un tipo nullable, verrà restituito 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);
    }

Ora puoi farlo:

Request.QueryString.GetValue<int?>(paramName) ?? 10;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top