Procedura: convertire in numeri l'input numerico dell'utente nei controlli Web
Aggiornamento: novembre 2007
Poiché una pagina Web può essere visualizzata in qualsiasi parte del mondo, gli utenti possono inserire dati numerici in un controllo TextBox utilizzando un numero quasi illimitato di formati. Di conseguenza, è molto importante determinare le impostazioni locali e le impostazioni cultura dell'utente della pagina Web, in modo da applicarne le convenzioni di formattazione quando si analizza l'input dell'utente.
Per convertire l'input numerico da un controllo Web TextBox in un numero
Determinare se la matrice di stringhe restituita dalla proprietà HttpRequest.UserLanguages è compilata. In caso contrario, andare al passaggio 6.
Se la matrice di stringhe restituita dalla proprietà UserLanguages è compilata, recuperarne il primo elemento. Il primo elemento indica la lingua e l'area predefinite o preferite dell'utente.
Creare un'istanza di un oggetto CultureInfo che rappresenta le impostazioni cultura preferite dell'utente chiamando il costruttore CultureInfo.CultureInfo(String, Boolean).
Chiamare TryParse o il metodo Parse del tipo numerico nel quale si desidera convertire l'input dell'utente. Utilizzare un overload del metodo TryParse o del metodo Parse con un parametro provider e passare uno degli elementi seguenti:
L'oggetto CultureInfo creato al passaggio 3.
L'oggetto NumberFormatInfo restituito dalla proprietà NumberFormat dell'oggetto CultureInfo creato al passaggio 3.
Se la conversione non riesce, ripetere i passaggi da 2 a 4 per ogni elemento rimanente nella matrice di stringhe restituita dalla proprietà UserLanguages.
Se la conversione ancora non riesce o se la matrice di stringhe restituita dalla proprietà UserLanguages è vuota, analizzare la stringa utilizzando la lingua inglese, restituita dalla proprietà CultureInfo.InvariantCulture.
Esempio
Nell'esempio seguente è riportata la pagina code-behind completa per un Web Form che richiede all'utente di immettere un valore numerico in un controllo TextBox e lo converte in un numero. Tale numero viene quindi raddoppiato e visualizzato utilizzando le stesse regole di formattazione dell'input originale.
Imports System.Globalization
Partial Class NumericUserInput
Inherits System.Web.UI.Page
Protected Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles OKButton.Click
Dim locale As String
Dim culture As CultureInfo = Nothing
Dim number As Double
Dim result As Boolean
' Exit if input is absent.
If String.IsNullOrEmpty(Me.NumericString.Text) Then Exit Sub
' Hide form elements.
Me.NumericInput.Visible = False
' Get user culture/region
If Not (Request.UserLanguages.Length = 0 OrElse String.IsNullOrEmpty(Request.UserLanguages(0))) Then
Try
locale = Request.UserLanguages(0)
culture = New CultureInfo(locale, False)
' Parse input using user culture.
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
Catch
End Try
' If parse fails, parse input using any additional languages.
If Not result Then
If Request.UserLanguages.Length > 1 Then
For ctr As Integer = 1 To Request.UserLanguages.Length - 1
Try
locale = Request.UserLanguages(ctr)
' Remove quality specifier, if present.
locale = Left(locale, InStr(locale, ";") - 1)
culture = New CultureInfo(Request.UserLanguages(ctr), False)
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
If result Then Exit For
Catch
End Try
Next
End If
End If
End If
' If parse operation fails, use invariant culture.
If Not result Then
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, number)
End If
' Double result
number *= 2
' Display result to user.
If result Then
Response.Write("<P />")
Response.Write(Server.HtmlEncode(Me.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />")
Else
' Unhide form.
Me.NumericInput.Visible = True
Response.Write("<P />")
Response.Write("Unable to recognize " + Server.HtmlEncode(Me.NumericString.Text))
End If
End Sub
End Class
using System;
using System.Globalization;
partial class NumericUserInput : System.Web.UI.Page
{
protected void OKButton_Click(object sender, EventArgs e)
{
string locale;
CultureInfo culture = null;
double number = 0;
bool result = false;
// Exit if input is absent.
if (String.IsNullOrEmpty(this.NumericString.Text)) return;
// Hide form elements.
this.NumericInput.Visible = false;
// Get user culture/region
if (!(Request.UserLanguages.Length == 0 || String.IsNullOrEmpty(Request.UserLanguages[0])))
{
try
{
locale = Request.UserLanguages[0];
culture = new CultureInfo(locale, false);
// Parse input using user culture.
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any,
culture.NumberFormat, out number);
}
catch { }
// If parse fails, parse input using any additional languages.
if (!result)
{
if (Request.UserLanguages.Length > 1)
{
for (int ctr = 1; ctr <= Request.UserLanguages.Length - 1; ctr++)
{
try
{
locale = Request.UserLanguages[ctr];
// Remove quality specifier, if present.
locale = locale.Substring(1, locale.IndexOf(';') - 1);
culture = new CultureInfo(Request.UserLanguages[ctr], false);
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, culture.NumberFormat, out number);
if (result) break;
}
catch { }
}
}
}
}
// If parse operation fails, use invariant culture.
if (!result)
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
// Double result.
number *= 2;
// Display result to user.
if (result)
{
Response.Write("<P />");
Response.Write(Server.HtmlEncode(this.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />");
}
else
{
// Unhide form.
this.NumericInput.Visible = true;
Response.Write("<P />");
Response.Write("Unable to recognize " + Server.HtmlEncode(this.NumericString.Text));
}
}
}
La proprietà HttpRequest.UserLanguages viene compilata con i nomi delle impostazioni cultura contenuti nelle intestazioni Accept-Language incluse in una richiesta HTTP. Non tutti i browser, tuttavia, includono intestazioni Accept-Language nelle rispettive richieste e inoltre le intestazioni possono essere del tutto rimosse dall'utente. Per questo motivo è importante disporre di impostazioni cultura di fallback durante l'analisi dell'input dell'utente. In genere le impostazioni cultura di fallback corrispondono alla lingua inglese restituita da CultureInfo.InvariantCulture. Gli utenti possono anche specificare i nomi delle impostazioni cultura in una casella di testo di Internet Explorer, rischiando tuttavia di inserire nomi non validi. È pertanto indispensabile utilizzare la gestione delle eccezioni durante la creazione di un'istanza di un oggetto CultureInfo.
Quando viene recuperata da una richiesta HTTP inviata da Internet Explorer, la matrice HttpRequest.UserLanguages viene compilata in base alla preferenza dell'utente. Il primo elemento della matrice contiene il nome delle impostazioni cultura/area primarie dell'utente. Se la matrice contiene elementi aggiuntivi, Internet Explorer assegna loro arbitrariamente un identificatore di qualità, separato dal nome delle impostazioni cultura con un punto e virgola. Una voce per le impostazioni cultura fr-FR può ad esempio avere il formato fr-FR;q=0.7.
Nell'esempio viene chiamato il costruttore CultureInfo il cui parametro useUserOverride è impostato su false per creare un nuovo oggetto CultureInfo. In questo modo, se il nome delle impostazioni cultura è il nome predefinito sul server, il nuovo oggetto CultureInfo creato dal costruttore della classe contiene le impostazioni cultura predefinite e non riflette le impostazioni sottoposte a override mediante l'applicazione Opzioni internazionali e della lingua del server. È improbabile che i valori delle impostazioni sottoposte a override sul server si trovino sul sistema dell'utente o vengano riflessi nell'input dell'utente.
Il codice può chiamare il metodo Parse o TryParse del tipo numerico nel quale verrà convertito l'input dell'utente. Chiamate ripetute a un metodo di analisi potrebbero richiedere una singola operazione di analisi. Di conseguenza, il metodo TryParse è preferibile in quanto restituisce false se un'operazione di analisi non riesce. Al contrario, la gestione delle eccezioni ripetute che possono essere generate dal metodo Parse può rappresentare una proposta piuttosto dispendiosa in un'applicazione Web.
Compilazione del codice
Per compilare il codice, copiarlo in una pagina code-behind di ASP.NET in modo che sostituisca tutto il codice esistente. La pagina Web ASP.NET deve contenere i controlli seguenti:
Un controllo Label al quale non viene fatto riferimento nel codice. Impostarne la proprietà Text su "Immettere un numero:".
Un controllo TextBox denominato NumericString.
Un controllo Button denominato OKButton. Impostarne la proprietà Text su "OK".
Modificare il nome della classe da NumericUserInput nel nome della classe definita dall'attributo Inherits della direttiva Page della pagina di ASP.NET. Modificare il nome del riferimento all'oggetto NumericInput nel nome definito dall'attributo id del tag form della pagina di ASP.NET.
Sicurezza
Per impedire che un utente inserisca uno script nel flusso HTML, l'input dell'utente non deve essere mai restituito direttamente nella risposta del server. Tale input deve essere invece codificato utilizzando il metodo HttpServerUtility.HtmlEncode.