Comment : convertir des entrées d'utilisateur numériques figurant dans des contrôles Web en nombres
Comme une page Web peut être affichée n'importe où dans le monde, les utilisateurs peuvent entrer des données numériques dans un contrôle TextBox dans un nombre presque illimité de formats. En conséquence, il est très important de déterminer les paramètres régionaux et la culture de l'utilisateur de la page Web. Lorsque vous analysez l'entrée d'utilisateur, vous pouvez ensuite appliquer les conventions de mise en forme définies par les paramètres régionaux et la culture de l'utilisateur.
Pour convertir l'entrée numérique d'un contrôle Web TextBox en un nombre
Déterminez si le tableau de chaînes retourné par la propriété HttpRequest.UserLanguages est rempli. Si ce n'est pas le cas, passez à l'étape 6.
Si le tableau de chaînes retourné par la propriété UserLanguages est rempli, récupérez son premier élément. Le premier élément indique la langue et la région par défaut ou préférées de l'utilisateur.
Instanciez un objet CultureInfo qui représente la culture par défaut de l'utilisateur en appelant le constructeur CultureInfo.CultureInfo(String, Boolean).
Appelez la méthode TryParse ou Parse du type numérique vers lequel vous souhaitez convertir l'entrée de l'utilisateur. Utilisez une surcharge de la méthode TryParse ou Parse avec un paramètre provider et passez-lui l'un ou l'autre des éléments suivants :
l'objet CultureInfo créé à l'étape 3 ;
l'objet NumberFormatInfo retourné par la propriété NumberFormat de l'objet CultureInfo créé à l'étape 3.
Si la conversion échoue, répétez les étapes 2 à 4 pour chaque élément restant du tableau de chaînes retourné par la propriété UserLanguages.
Si la conversion échoue encore ou si le tableau de chaînes retourné par la propriété UserLanguages est vide, analysez la chaîne en utilisant la culture indifférente retournée par la propriété CultureInfo.InvariantCulture.
Exemple
L'exemple suivant illustre la page code-behind complète d'un formulaire Web qui demande à l'utilisateur d'entrer une valeur numérique dans un contrôle TextBox et le convertit en un nombre. Ce nombre est ensuite doublé et affiché à l'aide des mêmes règles de mise en forme que l'entrée d'origine.
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 propriété HttpRequest.UserLanguages est remplie à l'aide des noms de culture contenus dans les en-têtes Accept-Language inclus dans une requête HTTP. Toutefois, certains navigateurs n'incluent pas d'en-têtes Accept-Language dans leurs demandes, et les utilisateurs peuvent également supprimer complètement les en-têtes. Il est donc important d'avoir une culture de secours lors de l'analyse de l'entrée d'utilisateur. En général, la culture de secours est la culture indifférente retournée par CultureInfo.InvariantCulture. Comme les utilisateurs peuvent également fournir à Internet Explorer des noms de culture qu'ils entrent dans une zone de texte, il peut arriver que ces noms ne soient pas valides. Il est donc important d'utiliser la gestion des exceptions lors de l'instanciation d'un objet CultureInfo.
Lorsqu'il est récupéré d'une requête HTTP soumise par Internet Explorer, le tableau HttpRequest.UserLanguages est rempli par ordre de préférence de l'utilisateur. Le premier élément du tableau comporte le nom de la culture/région principale de l'utilisateur. Si le tableau contient des éléments supplémentaires, Internet Explorer leur assigne arbitrairement un spécificateur de qualité séparé du nom de culture par un point-virgule. Par exemple, une entrée de la culture fr-FR peut se présenter sous la forme fr-FR;q=0.7.
L'exemple appelle le constructeur CultureInfo avec son paramètre useUserOverride défini à false pour créer un objet CultureInfo. Ceci garantit que, si le nom de culture est celui utilisé par défaut sur le serveur, le nouvel objet CultureInfo créé par le constructeur de classe contient les paramètres par défaut d'une culture et ne reflète pas les paramètres substitués à l'aide de l'application Options régionales et linguistiques du serveur. Il est peu probable que les valeurs des paramètres substitués sur le serveur existent sur le système de l'utilisateur ou qu'elles apparaissent dans l'entrée de l'utilisateur.
Votre code peut appeler la méthode Parse ou TryParse du type numérique vers lequel l'entrée de l'utilisateur sera convertie. Il se peut que vous deviez répéter les appels à une méthode d'analyse si vous effectuez une seule opération d'analyse. Par conséquent, en cas d'échec d'une opération d'analyse, il est préférable d'utiliser la méthode TryParse, car elle retourne la valeur false. En revanche, la gestion des exceptions répétées pouvant être levées par la méthode Parse risque d'être très onéreuse dans une application Web.
Compilation du code
Pour compiler le code, copiez-le dans une page code-behind ASP.NET afin de remplacer tout le code existant. La page Web ASP.NET doit contenir les contrôles suivants :
un contrôle Label qui n'est pas référencé dans le code (affectez la valeur "Enter a Number:" à sa propriété Text) ;
un contrôle TextBox nommé NumericString ;
un contrôle Button nommé OKButton (affectez la valeur "OK" à sa propriété Text).
Remplacez le nom de la classe NumericUserInput par celui défini par l'attribut Inherits de la directive Page de la page ASP.NET. Remplacez le nom de la référence d'objet NumericInput par celui défini par l'attribut id de la balise form de la page ASP.NET.
Sécurité
Pour empêcher l'injection de script dans le flux de données HTML, l'entrée d'utilisateur ne doit jamais être répétée directement dans la réponse du serveur, mais encodée à l'aide de la méthode HttpServerUtility.HtmlEncode.